📄 inode.c
字号:
// this is called to create file map. So, _get_block_create_0 will not// read direct itemint reiserfs_bmap (struct inode * inode, long block, struct buffer_head * bh_result, int create){ if (!file_capable (inode, block)) return -EFBIG; lock_kernel() ; /* do not read the direct item */ _get_block_create_0 (inode, block, bh_result, 0) ; unlock_kernel() ; return 0;}/* special version of get_block that is only used by grab_tail_page right** now. It is sent to block_prepare_write, and when you try to get a** block past the end of the file (or a block from a hole) it returns** -ENOENT instead of a valid buffer. block_prepare_write expects to** be able to do i/o on the buffers returned, unless an error value** is also returned.** ** So, this allows block_prepare_write to be used for reading a single block** in a page. Where it does not produce a valid page for holes, or past the** end of the file. This turns out to be exactly what we need for reading** tails for conversion.**** The point of the wrapper is forcing a certain value for create, even** though the VFS layer is calling this function with create==1. If you ** don't want to send create == GET_BLOCK_NO_HOLE to reiserfs_get_block, ** don't use this function.*/static int reiserfs_get_block_create_0 (struct inode * inode, long block, struct buffer_head * bh_result, int create) { return reiserfs_get_block(inode, block, bh_result, GET_BLOCK_NO_HOLE) ;}/*** helper function for when reiserfs_get_block is called for a hole** but the file tail is still in a direct item** bh_result is the buffer head for the hole** tail_offset is the offset of the start of the tail in the file**** This calls prepare_write, which will start a new transaction** you should not be in a transaction, or have any paths held when you** call this.*/static int convert_tail_for_hole(struct inode *inode, struct buffer_head *bh_result, loff_t tail_offset) { unsigned long index ; unsigned long tail_end ; unsigned long tail_start ; struct page * tail_page ; struct page * hole_page = bh_result->b_page ; int retval = 0 ; if ((tail_offset & (bh_result->b_size - 1)) != 1) return -EIO ; /* always try to read until the end of the block */ tail_start = tail_offset & (PAGE_CACHE_SIZE - 1) ; tail_end = (tail_start | (bh_result->b_size - 1)) + 1 ; index = tail_offset >> PAGE_CACHE_SHIFT ; if (index != hole_page->index) { tail_page = grab_cache_page(inode->i_mapping, index) ; retval = -ENOMEM; if (!tail_page) { goto out ; } } else { tail_page = hole_page ; } /* we don't have to make sure the conversion did not happen while ** we were locking the page because anyone that could convert ** must first take i_sem. ** ** We must fix the tail page for writing because it might have buffers ** that are mapped, but have a block number of 0. This indicates tail ** data that has been read directly into the page, and block_prepare_write ** won't trigger a get_block in this case. */ fix_tail_page_for_writing(tail_page) ; retval = block_prepare_write(tail_page, tail_start, tail_end, reiserfs_get_block) ; if (retval) goto unlock ; /* tail conversion might change the data in the page */ flush_dcache_page(tail_page) ; retval = generic_commit_write(NULL, tail_page, tail_start, tail_end) ;unlock: if (tail_page != hole_page) { UnlockPage(tail_page) ; page_cache_release(tail_page) ; }out: return retval ;}static inline int _allocate_block(struct reiserfs_transaction_handle *th, struct inode *inode, b_blocknr_t *allocated_block_nr, unsigned long tag, int flags) { #ifdef REISERFS_PREALLOCATE if (!(flags & GET_BLOCK_NO_ISEM)) { return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, tag); }#endif return reiserfs_new_unf_blocknrs (th, allocated_block_nr, tag);}//// initially this function was derived from ext2's analog and evolved// as the prototype did. You'll need to look at the ext2 version to// determine which parts are derivative, if any, understanding that// there are only so many ways to code to a given interface.//static int reiserfs_get_block (struct inode * inode, long block, struct buffer_head * bh_result, int create){ int repeat, retval; unsigned long tag; b_blocknr_t allocated_block_nr = 0;// b_blocknr_t is unsigned long INITIALIZE_PATH(path); int pos_in_item; struct cpu_key key; struct buffer_head * bh, * unbh = 0; struct item_head * ih, tmp_ih; __u32 * item; int done; int fs_gen; int windex ; struct reiserfs_transaction_handle th ; /* space reserved in transaction batch: . 3 balancings in direct->indirect conversion . 1 block involved into reiserfs_update_sd() XXX in practically impossible worst case direct2indirect() can incur (much) more that 3 balancings. */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1; int version; int transaction_started = 0 ; loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ; /* bad.... */ lock_kernel() ; th.t_trans_id = 0 ; version = get_inode_item_key_version (inode); if (block < 0) { unlock_kernel(); return -EIO; } if (!file_capable (inode, block)) { unlock_kernel() ; return -EFBIG; } /* if !create, we aren't changing the FS, so we don't need to ** log anything, so we don't need to start a transaction */ if (!(create & GET_BLOCK_CREATE)) { int ret ; /* find number of block-th logical block of the file */ ret = _get_block_create_0 (inode, block, bh_result, create | GET_BLOCK_READ_DIRECT) ; unlock_kernel() ; return ret; } inode->u.reiserfs_i.i_flags |= i_pack_on_close_mask; windex = push_journal_writer("reiserfs_get_block") ; /* set the key of the first byte in the 'block'-th block of file */ make_cpu_key (&key, inode, new_offset, TYPE_ANY, 3/*key length*/); if ((new_offset + inode->i_sb->s_blocksize - 1) > inode->i_size) { journal_begin(&th, inode->i_sb, jbegin_count) ; reiserfs_update_inode_transaction(inode) ; transaction_started = 1 ; } research: retval = search_for_position_by_key (inode->i_sb, &key, &path); if (retval == IO_ERROR) { retval = -EIO; goto failure; } bh = get_last_bh (&path); ih = get_ih (&path); item = get_item (&path); pos_in_item = path.pos_in_item; fs_gen = get_generation (inode->i_sb); copy_item_head (&tmp_ih, ih); if (allocation_needed (retval, allocated_block_nr, ih, item, pos_in_item)) { /* we have to allocate block for the unformatted node */ tag = find_tag (bh, ih, item, pos_in_item); if (!transaction_started) { pathrelse(&path) ; journal_begin(&th, inode->i_sb, jbegin_count) ; reiserfs_update_inode_transaction(inode) ; transaction_started = 1 ; goto research ; } repeat = _allocate_block(&th, inode, &allocated_block_nr, tag, create); if (repeat == NO_DISK_SPACE) { /* restart the transaction to give the journal a chance to free ** some blocks. releases the path, so we have to go back to ** research if we succeed on the second try */ restart_transaction(&th, inode, &path) ; repeat = _allocate_block(&th, inode,&allocated_block_nr,tag,create); if (repeat != NO_DISK_SPACE) { goto research ; } retval = -ENOSPC; goto failure; } if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) { goto research; } } if (indirect_item_found (retval, ih)) { b_blocknr_t unfm_ptr; /* 'block'-th block is in the file already (there is corresponding cell in some indirect item). But it may be zero unformatted node pointer (hole) */ unfm_ptr = get_block_num (item, pos_in_item); if (unfm_ptr == 0) { /* use allocated block to plug the hole */ reiserfs_prepare_for_journal(inode->i_sb, bh, 1) ; if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) { reiserfs_restore_prepared_buffer(inode->i_sb, bh) ; goto research; } bh_result->b_state |= (1UL << BH_New); put_block_num(item, pos_in_item, allocated_block_nr) ; unfm_ptr = allocated_block_nr; journal_mark_dirty (&th, inode->i_sb, bh); inode->i_blocks += (inode->i_sb->s_blocksize / 512) ; reiserfs_update_sd(&th, inode) ; } set_block_dev_mapped(bh_result, unfm_ptr, inode); pathrelse (&path); pop_journal_writer(windex) ; if (transaction_started) journal_end(&th, inode->i_sb, jbegin_count) ; unlock_kernel() ; /* the item was found, so new blocks were not added to the file ** there is no need to make sure the inode is updated with this ** transaction */ return 0; } if (!transaction_started) { /* if we don't pathrelse, we could vs-3050 on the buffer if ** someone is waiting for it (they can't finish until the buffer ** is released, we can start a new transaction until they finish) */ pathrelse(&path) ; journal_begin(&th, inode->i_sb, jbegin_count) ; reiserfs_update_inode_transaction(inode) ; transaction_started = 1 ; goto research; } /* desired position is not found or is in the direct item. We have to append file with holes up to 'block'-th block converting direct items to indirect one if necessary */ done = 0; do { if (is_statdata_le_ih (ih)) { __u32 unp = 0; struct cpu_key tmp_key; /* indirect item has to be inserted */ make_le_item_head (&tmp_ih, &key, version, 1, TYPE_INDIRECT, UNFM_P_SIZE, 0/* free_space */); if (cpu_key_k_offset (&key) == 1) { /* we are going to add 'block'-th block to the file. Use allocated block for that */ unp = cpu_to_le32 (allocated_block_nr); set_block_dev_mapped (bh_result, allocated_block_nr, inode); bh_result->b_state |= (1UL << BH_New); done = 1; } tmp_key = key; // ;) set_cpu_key_k_offset (&tmp_key, 1); PATH_LAST_POSITION(&path) ++; retval = reiserfs_insert_item (&th, &path, &tmp_key, &tmp_ih, (char *)&unp); if (retval) { reiserfs_free_block (&th, allocated_block_nr); goto failure; // retval == -ENOSPC or -EIO or -EEXIST } if (unp) inode->i_blocks += inode->i_sb->s_blocksize / 512; //mark_tail_converted (inode); } else if (is_direct_le_ih (ih)) { /* direct item has to be converted */ loff_t tail_offset; tail_offset = ((le_ih_k_offset (ih) - 1) & ~(inode->i_sb->s_blocksize - 1)) + 1; if (tail_offset == cpu_key_k_offset (&key)) { /* direct item we just found fits into block we have to map. Convert it into unformatted node: use bh_result for the conversion */ set_block_dev_mapped (bh_result, allocated_block_nr, inode); unbh = bh_result; done = 1; } else { /* we have to padd file tail stored in direct item(s) up to block size and convert it to unformatted node. FIXME: this should also get into page cache */ pathrelse(&path) ; journal_end(&th, inode->i_sb, jbegin_count) ; transaction_started = 0 ; retval = convert_tail_for_hole(inode, bh_result, tail_offset) ; if (retval) { printk("clm-6004: convert tail failed inode %lu, error %d\n", inode->i_ino, retval) ; if (allocated_block_nr) reiserfs_free_block (&th, allocated_block_nr); goto failure ; } goto research ; } retval = direct2indirect (&th, inode, &path, unbh, tail_offset); /* it is important the mark_buffer_uptodate is done after ** the direct2indirect. The buffer might contain valid ** data newer than the data on disk (read by readpage, changed, ** and then sent here by writepage). direct2indirect needs ** to know if unbh was already up to date, so it can decide ** if the data in unbh needs to be replaced with data from ** the disk */ mark_buffer_uptodate (unbh, 1); if (retval) { reiserfs_free_block (&th, allocated_block_nr); goto failure; } /* we've converted the tail, so we must ** flush unbh before the transaction commits */ add_to_flushlist(inode, unbh) ; /* mark it dirty now to prevent commit_write from adding ** this buffer to the inode's dirty buffer list */ __mark_buffer_dirty(unbh) ; //inode->i_blocks += inode->i_sb->s_blocksize / 512; //mark_tail_converted (inode); } else { /* append indirect item with holes if needed, when appending pointer to 'block'-th block use block, which is already allocated */ struct cpu_key tmp_key; struct unfm_nodeinfo un = {0, 0}; RFALSE( pos_in_item != ih_item_len(ih) / UNFM_P_SIZE, "vs-804: invalid position for append"); /* indirect item has to be appended, set up key of that position */ make_cpu_key (&tmp_key, inode, le_key_k_offset (version, &(ih->ih_key)) + op_bytes_number (ih, inode->i_sb->s_blocksize), //pos_in_item * inode->i_sb->s_blocksize, TYPE_INDIRECT, 3);// key type is unimportant if (cpu_key_k_offset (&tmp_key) == cpu_key_k_offset (&key)) { /* we are going to add target block to the file. Use allocated block for that */ un.unfm_nodenum = cpu_to_le32 (allocated_block_nr); set_block_dev_mapped (bh_result, allocated_block_nr, inode); bh_result->b_state |= (1UL << BH_New); done = 1; } else { /* paste hole to the indirect item */ } retval = reiserfs_paste_into_item (&th, &path, &tmp_key, (char *)&un, UNFM_P_SIZE); if (retval) { reiserfs_free_block (&th, allocated_block_nr); goto failure; } if (un.unfm_nodenum) inode->i_blocks += inode->i_sb->s_blocksize / 512; //mark_tail_converted (inode);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -