📄 inode.c
字号:
} 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 */ if (current->need_resched) schedule() ; 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 ("vs-825: reiserfs_get_block: " "%K should not be found\n", &key); retval = -EEXIST; if (allocated_block_nr) reiserfs_free_block (&th, allocated_block_nr); 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; reiserfs_check_path(&path) ; failure: if (transaction_started) { reiserfs_update_sd(&th, inode) ; journal_end(&th, inode->i_sb, jbegin_count) ; } pop_journal_writer(windex) ; unlock_kernel() ; reiserfs_check_path(&path) ; return retval;}//// 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_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 = PAGE_SIZE; INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ; 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 = sd_v1_atime(sd); inode->i_mtime = sd_v1_mtime(sd); inode->i_ctime = sd_v1_ctime(sd); 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_blksize >> 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); inode->u.reiserfs_i.i_first_direct_byte = sd_v1_first_direct_byte(sd); } 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 = sd_v2_mtime(sd); inode->i_atime = sd_v2_atime(sd); inode->i_ctime = sd_v2_ctime(sd); 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); set_inode_sd_version (inode, STAT_DATA_V2); } /* nopack = 0, by default */ inode->u.reiserfs_i.i_flags &= ~i_nopack_mask; 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 = &page_symlink_inode_operations; inode->i_mapping->a_ops = &reiserfs_address_space_operations; } else { inode->i_blocks = 0; init_special_inode(inode, inode->i_mode, rdev) ; }}// update new stat data with inode fieldsstatic void inode2sd (void * sd, struct inode * inode){ struct stat_data * sd_v2 = (struct stat_data *)sd; 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, inode->i_size ); set_sd_v2_gid(sd_v2, inode->i_gid ); set_sd_v2_mtime(sd_v2, inode->i_mtime ); set_sd_v2_atime(sd_v2, inode->i_atime ); set_sd_v2_ctime(sd_v2, inode->i_ctime ); set_sd_v2_blocks(sd_v2, inode->i_blocks ); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { set_sd_v2_rdev(sd_v2, inode->i_rdev );} else { set_sd_v2_generation(sd_v2, inode->i_generation); }}// used to copy inode's fields to old stat datastatic void inode2sd_v1 (void * sd, struct inode * inode){ 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, inode->i_size ); set_sd_v1_atime(sd_v1, inode->i_atime ); set_sd_v1_ctime(sd_v1, inode->i_ctime ); set_sd_v1_mtime(sd_v1, inode->i_mtime ); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) set_sd_v1_rdev(sd_v1, inode->i_rdev ); else set_sd_v1_blocks(sd_v1, inode->i_blocks ); // Sigh. i_first_direct_byte is back set_sd_v1_first_direct_byte(sd_v1, inode->u.reiserfs_i.i_first_direct_byte);}/* NOTE, you must prepare the buffer head before sending it here,** and then log it after the call*/static void update_stat_data (struct path * path, struct inode * inode){ struct buffer_head * bh; struct item_head * ih; bh = PATH_PLAST_BUFFER (path); ih = PATH_PITEM_HEAD (path); if (!is_statdata_le_ih (ih)) reiserfs_panic (inode->i_sb, "vs-13065: update_stat_data: key %k, found item %h", INODE_PKEY (inode), ih); if (stat_data_v1 (ih)) { // path points to old stat data inode2sd_v1 (B_I_PITEM (bh, ih), inode); } else { inode2sd (B_I_PITEM (bh, ih), inode); } return;}void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode){ struct cpu_key key; INITIALIZE_PATH(path); struct buffer_head *bh ; int fs_gen ; struct item_head *ih, tmp_ih ; int retval; make_cpu_key (&key, inode, SD_OFFSET, TYPE_STAT_DATA, 3);//key type is unimportant for(;;) { int pos; /* look for the object's stat data */ retval = search_item (inode->i_sb, &key, &path); if (retval == IO_ERROR) { reiserfs_warning ("vs-13050: reiserfs_update_sd: " "i/o failure occurred trying to update %K stat data", &key); return; } if (retval == ITEM_NOT_FOUND) { pos = PATH_LAST_POSITION (&path); pathrelse(&path) ; if (inode->i_nlink == 0) { /*printk ("vs-13050: reiserfs_update_sd: i_nlink == 0, stat data not found\n");*/ return; } reiserfs_warning ("vs-13060: reiserfs_update_sd: " "stat data of object %k (nlink == %d) not found (pos %d)\n", INODE_PKEY (inode), inode->i_nlink, pos); reiserfs_check_path(&path) ; return; } /* sigh, prepare_for_journal might schedule. When it schedules the ** FS might change. We have to detect that, and loop back to the ** search if the stat data item has moved */ bh = get_last_bh(&path) ; ih = get_ih(&path) ; copy_item_head (&tmp_ih, ih); fs_gen = get_generation (inode->i_sb); 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) ; continue ; /* Stat_data item has been moved after scheduling. */ } break; } update_stat_data (&path, inode); journal_mark_dirty(th, th->t_super, bh) ; pathrelse (&path); return;}void reiserfs_read_inode(struct inode *inode) { make_bad_inode(inode) ;}//// initially this function was derived from minix or ext2's analog and// evolved as the prototype did///* looks for stat data in the tree, and fills up the fields of in-core inode stat data fields */void reiserfs_read_inode2 (struct inode * inode, void *p){ INITIALIZE_PATH (path_to_sd); struct cpu_key key; struct reiserfs_iget4_args *args = (struct reiserfs_iget4_args *)p ; unsigned long dirino; int retval; if (!p) { make_bad_inode(inode) ; return; } dirino = args->objectid ; /* set version 1, version 2 could be used too, because stat data key is the same in both versions */ key.version = KEY_FORMAT_3_5; key.on_disk_key.k_dir_id = dirino; key.on_disk_key.k_objectid = inode->i_ino; key.on_disk_key.u.k_offset_v1.k_offset = SD_OFFSET; key.on_disk_key.u.k_offset_v1.k_uniqueness = SD_UNIQUENESS; /* look for the object's stat data */ retval = search_item (inode->i_sb, &key, &path_to_sd); if (retval == IO_ERROR) { reiserfs_warning ("vs-13070: reiserfs_read_inode2: " "i/o failure occurred trying to find stat data of %K\n", &key); make_bad_inode(inode) ; return; } if (retval != ITEM_FOUND) { /* a stale NFS handle can trigger this without it being an error */ pathrelse (&path_to_sd); make_bad_inode(inode) ; inode->i_nlink = 0; return; } init_inode (inode, &path_to_sd); /* It is possible that knfsd is trying to access inode of a file that is being removed from the disk by some other thread. As we update sd on unlink all that is required is to check for nlink here. This bug was first found by Sizif when debugging SquidNG/Butterfly, forgotten, and found again after Philippe Gramoulle <philippe.gramoulle@mmania.com> reproduced it. More logical fix would require changes in fs/inode.c:iput() to remove inode from hash-table _after_ fs cleaned disk stuff up and in iget() to return NULL if I_FREEING inode is found in hash-table. */ /* Currently there is one place where it's ok to meet inode with nlink==0: processing of open-unlinked and half-truncated files during mount (fs/reiserfs/super.c:finish_unfinished()). */ if( ( inode -> i_nlink == 0 ) && ! inode -> i_sb -> u.reiserfs_sb.s_is_unlinked_ok ) { reiserfs_warning( "vs-13075: reiserfs_read_inode2: " "dead inode read from disk %K. " "This is likely to be race with knfsd. Ignore\n", &key ); make_bad_inode( inode ); } reiserfs_check_path(&path_to_sd) ; /* init inode should be relsing */}/** * reiserfs_find_actor() - "find actor" reiserfs supplies to iget4(). * * @inode: inode from hash table to check * @inode_no: inode number we are looking for * @opaque: "cookie" passed to iget4(). This is &reiserfs_iget4_args. * * This function is called by iget4() to distinguish reiserfs inodes * having the same inode numbers. Such inodes can only exist due to some * error condition. One of them should be bad. Inodes with identical * inode numbers (objectids) are distinguished by parent directory ids. * */static int reiserfs_find_actor( struct inode *inode, unsigned long inode_no, void *opaque ){ struct reiserfs_iget4_args *args; args = opaque; /* args is already in CPU order */ return le32_to_cpu(INODE_PKEY(inode)->k_dir_id) == args -> objectid;}struct inode * reiserfs_iget (struct super_block * s, const struct cpu_key * key){ struct inode * inode; struct reiserfs_iget4_args args ; args.objectid = key->on_disk_key.k_dir_id ; inode = iget4 (s, key->on_disk_key.k_objectid, reiserfs_find_actor, (void *)(&args)); if (!inode) return ERR_PTR(-ENOMEM) ; if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -