⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inode.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
// 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 + -