📄 inode.c
字号:
** On success, page_result is set to a locked, pinned page, and bh_result** is set to an up to date buffer for the last block in the file. returns 0.**** tail conversion is not done, so bh_result might not be valid for writing** check buffer_mapped(bh_result) and bh_result->b_blocknr != 0 before** trying to write the block.**** on failure, nonzero is returned, page_result and bh_result are untouched.*/static int grab_tail_page(struct inode *p_s_inode, struct page **page_result, struct buffer_head **bh_result) { /* we want the page with the last byte in the file, ** not the page that will hold the next byte for appending */ unsigned long index = (p_s_inode->i_size-1) >> PAGE_CACHE_SHIFT ; unsigned long pos = 0 ; unsigned long start = 0 ; unsigned long blocksize = p_s_inode->i_sb->s_blocksize ; unsigned long offset = (p_s_inode->i_size) & (PAGE_CACHE_SIZE - 1) ; struct buffer_head *bh ; struct buffer_head *head ; struct page * page ; int error ; /* we know that we are only called with inode->i_size > 0. ** we also know that a file tail can never be as big as a block ** If i_size % blocksize == 0, our file is currently block aligned ** and it won't need converting or zeroing after a truncate. */ if ((offset & (blocksize - 1)) == 0) { return -ENOENT ; } page = grab_cache_page(p_s_inode->i_mapping, index) ; error = -ENOMEM ; if (!page) { goto out ; } /* start within the page of the last block in the file */ start = (offset / blocksize) * blocksize ; error = block_prepare_write(page, start, offset, reiserfs_get_block_create_0) ; if (error) goto unlock ; kunmap(page) ; /* mapped by block_prepare_write */ head = page->buffers ; bh = head; do { if (pos >= start) { break ; } bh = bh->b_this_page ; pos += blocksize ; } while(bh != head) ; if (!buffer_uptodate(bh)) { /* note, this should never happen, prepare_write should ** be taking care of this for us. If the buffer isn't up to date, ** I've screwed up the code to find the buffer, or the code to ** call prepare_write */ reiserfs_warning("clm-6000: error reading block %lu on dev %s\n", bh->b_blocknr, kdevname(bh->b_dev)) ; error = -EIO ; goto unlock ; } *bh_result = bh ; *page_result = page ;out: return error ;unlock: UnlockPage(page) ; page_cache_release(page) ; return error ;}/*** vfs version of truncate file. Must NOT be called with** a transaction already started.**** some code taken from block_truncate_page*/void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) { struct reiserfs_transaction_handle th ; int windex ; /* we want the offset for the first byte after the end of the file */ unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1) ; unsigned blocksize = p_s_inode->i_sb->s_blocksize ; unsigned length ; struct page *page = NULL ; int error ; struct buffer_head *bh = NULL ; if (p_s_inode->i_size > 0) { if ((error = grab_tail_page(p_s_inode, &page, &bh))) { // -ENOENT means we truncated past the end of the file, // and get_block_create_0 could not find a block to read in, // which is ok. if (error != -ENOENT) reiserfs_warning("clm-6001: grab_tail_page failed %d\n", error); page = NULL ; bh = NULL ; } } /* so, if page != NULL, we have a buffer head for the offset at ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0, ** then we have an unformatted node. Otherwise, we have a direct item, ** and no zeroing is required on disk. We zero after the truncate, ** because the truncate might pack the item anyway ** (it will unmap bh if it packs). */ /* it is enough to reserve space in transaction for 2 balancings: one for "save" link adding and another for the first cut_from_item. 1 is for update_sd */ journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ; reiserfs_update_inode_transaction(p_s_inode) ; windex = push_journal_writer("reiserfs_vfs_truncate_file") ; if (update_timestamps) /* we are doing real truncate: if the system crashes before the last transaction of truncating gets committed - on reboot the file either appears truncated properly or not truncated at all */ add_save_link (&th, p_s_inode, 1); reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ; pop_journal_writer(windex) ; journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ; if (update_timestamps) remove_save_link (p_s_inode, 1/* truncate */); if (page) { length = offset & (blocksize - 1) ; /* if we are not on a block boundary */ if (length) { length = blocksize - length ; memset((char *)kmap(page) + offset, 0, length) ; flush_dcache_page(page) ; kunmap(page) ; if (buffer_mapped(bh) && bh->b_blocknr != 0) { mark_buffer_dirty(bh) ; } } UnlockPage(page) ; page_cache_release(page) ; } return ;}static int map_block_for_writepage(struct inode *inode, struct buffer_head *bh_result, unsigned long block) { struct reiserfs_transaction_handle th ; int fs_gen ; struct item_head tmp_ih ; struct item_head *ih ; struct buffer_head *bh ; __u32 *item ; struct cpu_key key ; INITIALIZE_PATH(path) ; int pos_in_item ; int jbegin_count = JOURNAL_PER_BALANCE_CNT ; loff_t byte_offset = (block << inode->i_sb->s_blocksize_bits) + 1 ; int retval ; int use_get_block = 0 ; int bytes_copied = 0 ; int copy_size ; kmap(bh_result->b_page) ;start_over: lock_kernel() ; journal_begin(&th, inode->i_sb, jbegin_count) ; reiserfs_update_inode_transaction(inode) ; make_cpu_key(&key, inode, byte_offset, TYPE_ANY, 3) ;research: retval = search_for_position_by_key(inode->i_sb, &key, &path) ; if (retval != POSITION_FOUND) { use_get_block = 1; goto out ; } bh = get_last_bh(&path) ; ih = get_ih(&path) ; item = get_item(&path) ; pos_in_item = path.pos_in_item ; /* we've found an unformatted node */ if (indirect_item_found(retval, ih)) { if (bytes_copied > 0) { reiserfs_warning("clm-6002: bytes_copied %d\n", bytes_copied) ; } if (!get_block_num(item, pos_in_item)) { /* crap, we are writing to a hole */ use_get_block = 1; goto out ; } set_block_dev_mapped(bh_result, get_block_num(item,pos_in_item),inode); mark_buffer_uptodate(bh_result, 1); } else if (is_direct_le_ih(ih)) { char *p ; p = page_address(bh_result->b_page) ; p += (byte_offset -1) & (PAGE_CACHE_SIZE - 1) ; copy_size = ih_item_len(ih) - pos_in_item; fs_gen = get_generation(inode->i_sb) ; copy_item_head(&tmp_ih, ih) ; 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; } memcpy( B_I_PITEM(bh, ih) + pos_in_item, p + bytes_copied, copy_size) ; journal_mark_dirty(&th, inode->i_sb, bh) ; bytes_copied += copy_size ; set_block_dev_mapped(bh_result, 0, inode); mark_buffer_uptodate(bh_result, 1); /* are there still bytes left? */ if (bytes_copied < bh_result->b_size && (byte_offset + bytes_copied) < inode->i_size) { set_cpu_key_k_offset(&key, cpu_key_k_offset(&key) + copy_size) ; goto research ; } } else { reiserfs_warning("clm-6003: bad item inode %lu, device %s\n", inode->i_ino, kdevname(inode->i_sb->s_dev)) ; retval = -EIO ; goto out ; } retval = 0 ; out: pathrelse(&path) ; journal_end(&th, inode->i_sb, jbegin_count) ; unlock_kernel() ; /* this is where we fill in holes in the file. */ if (use_get_block) { retval = reiserfs_get_block(inode, block, bh_result, GET_BLOCK_CREATE | GET_BLOCK_NO_ISEM) ; if (!retval) { if (!buffer_mapped(bh_result) || bh_result->b_blocknr == 0) { /* get_block failed to find a mapped unformatted node. */ use_get_block = 0 ; goto start_over ; } } } kunmap(bh_result->b_page) ; return retval ;}/* helper func to get a buffer head ready for writepage to send to** ll_rw_block*/static inline void submit_bh_for_writepage(struct buffer_head **bhp, int nr) { struct buffer_head *bh ; int i; for(i = 0 ; i < nr ; i++) { bh = bhp[i] ; lock_buffer(bh) ; set_buffer_async_io(bh) ; /* submit_bh doesn't care if the buffer is dirty, but nobody ** later on in the call chain will be cleaning it. So, we ** clean the buffer here, it still gets written either way. */ clear_bit(BH_Dirty, &bh->b_state) ; set_bit(BH_Uptodate, &bh->b_state) ; submit_bh(WRITE, bh) ; }}static int reiserfs_write_full_page(struct page *page) { struct inode *inode = page->mapping->host ; unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT ; unsigned last_offset = PAGE_CACHE_SIZE; int error = 0; unsigned long block ; unsigned cur_offset = 0 ; struct buffer_head *head, *bh ; int partial = 0 ; struct buffer_head *arr[PAGE_CACHE_SIZE/512] ; int nr = 0 ; if (!page->buffers) { block_prepare_write(page, 0, 0, NULL) ; kunmap(page) ; } /* last page in the file, zero out any contents past the ** last byte in the file */ if (page->index >= end_index) { last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1) ; /* no file contents in this page */ if (page->index >= end_index + 1 || !last_offset) { error = -EIO ; goto fail ; } memset((char *)kmap(page)+last_offset, 0, PAGE_CACHE_SIZE-last_offset) ; flush_dcache_page(page) ; kunmap(page) ; } head = page->buffers ; bh = head ; block = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits) ; do { /* if this offset in the page is outside the file */ if (cur_offset >= last_offset) { if (!buffer_uptodate(bh)) partial = 1 ; } else { /* fast path, buffer mapped to an unformatted node */ if (buffer_mapped(bh) && bh->b_blocknr != 0) { arr[nr++] = bh ; } else { /* buffer not mapped yet, or points to a direct item. ** search and dirty or log */ if ((error = map_block_for_writepage(inode, bh, block))) { goto fail ; } /* map_block_for_writepage either found an unformatted node ** and mapped it for us, or it found a direct item ** and logged the changes. */ if (buffer_mapped(bh) && bh->b_blocknr != 0) { arr[nr++] = bh ; } } } bh = bh->b_this_page ; cur_offset += bh->b_size ; block++ ; } while(bh != head) ; /* if this page only had a direct item, it is very possible for ** nr == 0 without there being any kind of error. */ if (nr) { submit_bh_for_writepage(arr, nr) ; } else { UnlockPage(page) ; } if (!partial) SetPageUptodate(page) ; return 0 ;fail: if (nr) { submit_bh_for_writepage(arr, nr) ; } else { UnlockPage(page) ; } ClearPageUptodate(page) ; return error ;}//// this is exactly what 2.3.99-pre9's ext2_readpage is//static int reiserfs_readpage (struct file *f, struct page * page){ return block_read_full_page (page, reiserfs_get_block);}//// modified from ext2_writepage is//static int reiserfs_writepage (struct page * page){ struct inode *inode = page->mapping->host ; reiserfs_wait_on_write_block(inode->i_sb) ; return reiserfs_write_full_page(page) ;}//// from ext2_prepare_write, but modified//int reiserfs_prepare_write(struct file *f, struct page *page, unsigned from, unsigned to) { struct inode *inode = page->mapping->host ; reiserfs_wait_on_write_block(inode->i_sb) ; fix_tail_page_for_writing(page) ; return block_prepare_write(page, from, to, reiserfs_get_block) ;}//// this is exactly what 2.3.99-pre9's ext2_bmap is//static int reiserfs_aop_bmap(struct address_space *as, long block) { return generic_block_bmap(as, block, reiserfs_bmap) ;}static
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -