inode.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,950 行 · 第 1/5 页

C
1,950
字号
			    th = reiserfs_persistent_transaction(inode->i_sb,3);			if (th)			    reiserfs_free_block (th,inode,allocated_block_nr,1);		    }		    goto failure ;		}		goto research ;	    }	    retval = direct2indirect (th, inode, &path, unbh, tail_offset);	    if (retval) {		reiserfs_unmap_buffer(unbh);		reiserfs_free_block (th, inode, allocated_block_nr, 1);		goto failure;	    }	    /* it is important the set_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	    */	    set_buffer_uptodate (unbh);	    /* unbh->b_page == NULL in case of DIRECT_IO request, this means	       buffer will disappear shortly, so it should not be added to	     */	    if ( unbh->b_page ) {		/* we've converted the tail, so we must		** flush unbh before the transaction commits		*/		reiserfs_add_tail_list(inode, unbh) ;		/* mark it dirty now to prevent commit_write from adding		** this buffer to the inode's dirty buffer list		*/		/*		 * AKPM: changed __mark_buffer_dirty to mark_buffer_dirty().		 * It's still atomic, but it sets the page dirty too,		 * which makes it eligible for writeback at any time by the		 * VM (which was also the case with __mark_buffer_dirty())		 */		mark_buffer_dirty(unbh) ;	    }	} 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;	    unp_t unf_single=0; // We use this in case we need to allocate only				// one block which is a fastpath	    unp_t *un;	    __u64 max_to_insert=MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE;	    __u64 blocks_needed;	    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	    blocks_needed = 1 + ((cpu_key_k_offset (&key) - cpu_key_k_offset (&tmp_key)) >> inode->i_sb->s_blocksize_bits);	    RFALSE( blocks_needed < 0, "green-805: invalid offset");	    if ( blocks_needed == 1 ) {		un = &unf_single;	    } else {		un=kmalloc( min(blocks_needed,max_to_insert)*UNFM_P_SIZE,			    GFP_ATOMIC); // We need to avoid scheduling.		if ( !un) {		    un = &unf_single;		    blocks_needed = 1;		    max_to_insert = 0;		} else		    memset(un, 0, UNFM_P_SIZE * min(blocks_needed,max_to_insert));	    }	    if ( blocks_needed <= max_to_insert) {		/* we are going to add target block to the file. Use allocated		   block for that */		un[blocks_needed-1] = cpu_to_le32 (allocated_block_nr);		set_block_dev_mapped (bh_result, allocated_block_nr, inode);		set_buffer_new(bh_result);		done = 1;	    } else {		/* paste hole to the indirect item */		/* If kmalloc failed, max_to_insert becomes zero and it means we		   only have space for one block */		blocks_needed=max_to_insert?max_to_insert:1;	    }	    retval = reiserfs_paste_into_item (th, &path, &tmp_key, inode, (char *)un, UNFM_P_SIZE * blocks_needed);	    if (blocks_needed != 1)		kfree(un);	    if (retval) {		reiserfs_free_block (th, inode, allocated_block_nr, 1);		goto failure;	    }	    if (!done) {		/* We need to mark new file size in case this function will be		   interrupted/aborted later on. And we may do this only for		   holes. */		inode->i_size += inode->i_sb->s_blocksize * blocks_needed;	    }	}	if (done == 1)	    break;	/* this loop could log more blocks than we had originally asked	** for.  So, we have to allow the transaction to end if it is	** too big or too full.  Update the inode so things are 	** consistent if we crash before the function returns	**	** release the path so that anybody waiting on the path before	** ending their transaction will be able to continue.	*/	if (journal_transaction_should_end(th, th->t_blocks_allocated)) {	  restart_transaction(th, inode, &path) ;	}	/* inserting indirect pointers for a hole can take a 	** long time.  reschedule if needed	*/	cond_resched();	retval = search_for_position_by_key (inode->i_sb, &key, &path);	if (retval == IO_ERROR) {	    retval = -EIO;	    goto failure;	}	if (retval == POSITION_FOUND) {	    reiserfs_warning (inode->i_sb, "vs-825: reiserfs_get_block: "			      "%K should not be found", &key);	    retval = -EEXIST;	    if (allocated_block_nr)	        reiserfs_free_block (th, inode, allocated_block_nr, 1);	    pathrelse(&path) ;	    goto failure;	}	bh = get_last_bh (&path);	ih = get_ih (&path);	item = get_item (&path);	pos_in_item = path.pos_in_item;    } while (1);    retval = 0; failure:    if (th && !dangle) {      reiserfs_update_sd(th, inode) ;      reiserfs_end_persistent_transaction(th);    }    reiserfs_write_unlock(inode->i_sb);    reiserfs_check_path(&path) ;    return retval;}static intreiserfs_readpages(struct file *file, struct address_space *mapping,		struct list_head *pages, unsigned nr_pages){    return mpage_readpages(mapping, pages, nr_pages, reiserfs_get_block);}/* Compute real number of used bytes by file * Following three functions can go away when we'll have enough space in stat item */static int real_space_diff(struct inode *inode, int sd_size){    int bytes;    loff_t blocksize = inode->i_sb->s_blocksize ;    if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode))        return sd_size ;    /* End of file is also in full block with indirect reference, so round    ** up to the next block.    **    ** there is just no way to know if the tail is actually packed    ** on the file, so we have to assume it isn't.  When we pack the    ** tail, we add 4 bytes to pretend there really is an unformatted    ** node pointer    */    bytes = ((inode->i_size + (blocksize-1)) >> inode->i_sb->s_blocksize_bits) * UNFM_P_SIZE + sd_size;    return bytes ;}static inline loff_t to_real_used_space(struct inode *inode, ulong blocks,                                        int sd_size){    if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {        return inode->i_size + (loff_t)(real_space_diff(inode, sd_size)) ;    }    return ((loff_t)real_space_diff(inode, sd_size)) + (((loff_t)blocks) << 9);}/* Compute number of blocks used by file in ReiserFS counting */static inline ulong to_fake_used_blocks(struct inode *inode, int sd_size){    loff_t bytes = inode_get_bytes(inode) ;    loff_t real_space = real_space_diff(inode, sd_size) ;    /* keeps fsck and non-quota versions of reiserfs happy */    if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {        bytes += (loff_t)511 ;    }    /* files from before the quota patch might i_blocks such that    ** bytes < real_space.  Deal with that here to prevent it from    ** going negative.    */    if (bytes < real_space)        return 0 ;    return (bytes - real_space) >> 9;}//// BAD: new directories have stat data of new type and all other items// of old type. Version stored in the inode says about body items, so// in update_stat_data we can not rely on inode, but have to check// item version directly//// called by read_locked_inodestatic void init_inode (struct inode * inode, struct path * path){    struct buffer_head * bh;    struct item_head * ih;    __u32 rdev;    //int version = ITEM_VERSION_1;    bh = PATH_PLAST_BUFFER (path);    ih = PATH_PITEM_HEAD (path);    copy_key (INODE_PKEY (inode), &(ih->ih_key));    inode->i_blksize = reiserfs_default_io_size;    INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list ));    REISERFS_I(inode)->i_flags = 0;    REISERFS_I(inode)->i_prealloc_block = 0;    REISERFS_I(inode)->i_prealloc_count = 0;    REISERFS_I(inode)->i_trans_id = 0;    REISERFS_I(inode)->i_jl = NULL;    REISERFS_I(inode)->i_acl_access = NULL;    REISERFS_I(inode)->i_acl_default = NULL;    init_rwsem (&REISERFS_I(inode)->xattr_sem);    if (stat_data_v1 (ih)) {	struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);	unsigned long blocks;	set_inode_item_key_version (inode, KEY_FORMAT_3_5);        set_inode_sd_version (inode, STAT_DATA_V1);	inode->i_mode  = sd_v1_mode(sd);	inode->i_nlink = sd_v1_nlink(sd);	inode->i_uid   = sd_v1_uid(sd);	inode->i_gid   = sd_v1_gid(sd);	inode->i_size  = sd_v1_size(sd);	inode->i_atime.tv_sec = sd_v1_atime(sd);	inode->i_mtime.tv_sec = sd_v1_mtime(sd);	inode->i_ctime.tv_sec = sd_v1_ctime(sd);	inode->i_atime.tv_nsec = 0;	inode->i_ctime.tv_nsec = 0;	inode->i_mtime.tv_nsec = 0;	inode->i_blocks = sd_v1_blocks(sd);	inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id);	blocks = (inode->i_size + 511) >> 9;	blocks = _ROUND_UP (blocks, inode->i_sb->s_blocksize >> 9);	if (inode->i_blocks > blocks) {	    // there was a bug in <=3.5.23 when i_blocks could take negative	    // values. Starting from 3.5.17 this value could even be stored in	    // stat data. For such files we set i_blocks based on file	    // size. Just 2 notes: this can be wrong for sparce files. On-disk value will be	    // only updated if file's inode will ever change	    inode->i_blocks = blocks;	}        rdev = sd_v1_rdev(sd);	REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd);	/* an early bug in the quota code can give us an odd number for the	** block count.  This is incorrect, fix it here.	*/	if (inode->i_blocks & 1) {	    inode->i_blocks++ ;	}	inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks,	                                          SD_V1_SIZE));	/* nopack is initially zero for v1 objects. For v2 objects,	   nopack is initialised from sd_attrs */	REISERFS_I(inode)->i_flags &= ~i_nopack_mask;    } else {	// new stat data found, but object may have old items	// (directories and symlinks)	struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih);	inode->i_mode   = sd_v2_mode(sd);	inode->i_nlink  = sd_v2_nlink(sd);	inode->i_uid    = sd_v2_uid(sd);	inode->i_size   = sd_v2_size(sd);	inode->i_gid    = sd_v2_gid(sd);	inode->i_mtime.tv_sec  = sd_v2_mtime(sd);	inode->i_atime.tv_sec = sd_v2_atime(sd);	inode->i_ctime.tv_sec  = sd_v2_ctime(sd);	inode->i_ctime.tv_nsec = 0;	inode->i_mtime.tv_nsec = 0;	inode->i_atime.tv_nsec = 0;	inode->i_blocks = sd_v2_blocks(sd);        rdev            = sd_v2_rdev(sd);	if( S_ISCHR( inode -> i_mode ) || S_ISBLK( inode -> i_mode ) )	    inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id);	else            inode->i_generation = sd_v2_generation(sd);	if (S_ISDIR (inode->i_mode) || S_ISLNK (inode->i_mode))	    set_inode_item_key_version (inode, KEY_FORMAT_3_5);	else	    set_inode_item_key_version (inode, KEY_FORMAT_3_6);	REISERFS_I(inode)->i_first_direct_byte = 0;	set_inode_sd_version (inode, STAT_DATA_V2);	inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks,	                                          SD_V2_SIZE));	/* read persistent inode attributes from sd and initalise	   generic inode flags from them */	REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd );	sd_attrs_to_i_attrs( sd_v2_attrs( sd ), inode );    }    pathrelse (path);    if (S_ISREG (inode->i_mode)) {	inode->i_op = &reiserfs_file_inode_operations;	inode->i_fop = &reiserfs_file_operations;	inode->i_mapping->a_ops = &reiserfs_address_space_operations ;    } else if (S_ISDIR (inode->i_mode)) {	inode->i_op = &reiserfs_dir_inode_operations;	inode->i_fop = &reiserfs_dir_operations;    } else if (S_ISLNK (inode->i_mode)) {	inode->i_op = &reiserfs_symlink_inode_operations;	inode->i_mapping->a_ops = &reiserfs_address_space_operations;    } else {	inode->i_blocks = 0;	inode->i_op = &reiserfs_special_inode_operations;	init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));    }}// update new stat data with inode fieldsstatic void inode2sd (void * sd, struct inode * inode, loff_t size){    struct stat_data * sd_v2 = (struct stat_data *)sd;    __u16 flags;    set_sd_v2_mode(sd_v2, inode->i_mode );    set_sd_v2_nlink(sd_v2, inode->i_nlink );    set_sd_v2_uid(sd_v2, inode->i_uid );    set_sd_v2_size(sd_v2, size );    set_sd_v2_gid(sd_v2, inode->i_gid );    set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec );    set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec );    set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec );    set_sd_v2_blocks(sd_v2, to_fake_used_blocks(inode, SD_V2_SIZE));    if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))	set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev));    else	set_sd_v2_generation(sd_v2, inode->i_generation);    flags = REISERFS_I(inode)->i_attrs;    i_attrs_to_sd_attrs( inode, &flags );    set_sd_v2_attrs( sd_v2, flags );}// used to copy inode's fields to old stat datastatic void inode2sd_v1 (void * sd, struct inode * inode, loff_t size){    struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)sd;    set_sd_v1_mode(sd_v1, inode->i_mode );    set_sd_v1_uid(sd_v1, inode->i_uid );    set_sd_v1_gid(sd_v1, inode->i_gid );    set_sd_v1_nlink(sd_v1, inode->i_nlink );    set_sd_v1_size(sd_v1, size );    set_sd_v1_atime(sd_v1, inode->i_atime.tv_sec );    set_sd_v1_ctime(sd_v1, inode->i_ctime.tv_sec );    set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec );

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?