/* The function is NOT SCHEDULE-SAFE! */ int search_for_position_by_key(struct reiserfs_sb_info *p_s_sbi, const struct cpu_key *p_cpu_key, /* Key to search (cpu variable) */ struct path *p_s_search_path) /* Filled up by this function. */ { int retval, n_blk_size; off_t item_offset, offset; struct item_head *p_le_ih; /* Pointer to on-disk structure */ struct reiserfs_dir_entry de; /* If searching for directory entry. */ if (is_direntry_cpu_key(p_cpu_key)) return (search_by_entry_key(p_s_sbi, p_cpu_key, p_s_search_path, &de)); /* If not searching for directory entry. */ /* If item is found. */ retval = search_item(p_s_sbi, p_cpu_key, p_s_search_path); if (retval == IO_ERROR) return (retval); if (retval == ITEM_FOUND) { if (ih_item_len(B_N_PITEM_HEAD( PATH_PLAST_BUFFER(p_s_search_path), PATH_LAST_POSITION(p_s_search_path))) == 0) { reiserfs_log(LOG_WARNING, "item length equals zero\n"); } pos_in_item(p_s_search_path) = 0; return (POSITION_FOUND); } if (PATH_LAST_POSITION(p_s_search_path) == 0) { reiserfs_log(LOG_WARNING, "position equals zero\n"); } /* Item is not found. Set path to the previous item. */ p_le_ih = B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path), --PATH_LAST_POSITION(p_s_search_path)); n_blk_size = p_s_sbi->s_blocksize; if (comp_short_keys(&(p_le_ih->ih_key), p_cpu_key)) { return (FILE_NOT_FOUND); } item_offset = le_ih_k_offset(p_le_ih); offset = cpu_key_k_offset(p_cpu_key); /* Needed byte is contained in the item pointed to by the path.*/ if (item_offset <= offset && item_offset + op_bytes_number(p_le_ih, n_blk_size) > offset) { pos_in_item(p_s_search_path) = offset - item_offset; if (is_indirect_le_ih(p_le_ih)) { pos_in_item(p_s_search_path) /= n_blk_size; } return (POSITION_FOUND); } /* Needed byte is not contained in the item pointed to by the * path. Set pos_in_item out of the item. */ if (is_indirect_le_ih(p_le_ih)) pos_in_item(p_s_search_path) = ih_item_len(p_le_ih) / UNFM_P_SIZE; else pos_in_item(p_s_search_path) = ih_item_len(p_le_ih); return (POSITION_NOT_FOUND); }
/* Allocates blocks for a file to fulfil write request. Maps all unmapped but prepared pages from the list. Updates metadata with newly allocated blocknumbers as needed */ int reiserfs_allocate_blocks_for_region( struct reiserfs_transaction_handle *th, struct inode *inode, /* Inode we work with */ loff_t pos, /* Writing position */ int num_pages, /* number of pages write going to touch */ int write_bytes, /* amount of bytes to write */ struct page **prepared_pages, /* array of prepared pages */ int blocks_to_allocate /* Amount of blocks we need to allocate to fit the data into file */ ) { struct cpu_key key; // cpu key of item that we are going to deal with struct item_head *ih; // pointer to item head that we are going to deal with struct buffer_head *bh; // Buffer head that contains items that we are going to deal with __u32 * item; // pointer to item we are going to deal with INITIALIZE_PATH(path); // path to item, that we are going to deal with. b_blocknr_t *allocated_blocks; // Pointer to a place where allocated blocknumbers would be stored. reiserfs_blocknr_hint_t hint; // hint structure for block allocator. size_t res; // return value of various functions that we call. int curr_block; // current block used to keep track of unmapped blocks. int i; // loop counter int itempos; // position in item unsigned int from = (pos & (PAGE_CACHE_SIZE - 1)); // writing position in // first page unsigned int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1; /* last modified byte offset in last page */ __u64 hole_size ; // amount of blocks for a file hole, if it needed to be created. int modifying_this_item = 0; // Flag for items traversal code to keep track // of the fact that we already prepared // current block for journal int will_prealloc = 0; RFALSE(!blocks_to_allocate, "green-9004: tried to allocate zero blocks?"); /* only preallocate if this is a small write */ if (REISERFS_I(inode)->i_prealloc_count || (!(write_bytes & (inode->i_sb->s_blocksize -1)) && blocks_to_allocate < REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize)) will_prealloc = REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize; allocated_blocks = kmalloc((blocks_to_allocate + will_prealloc) * sizeof(b_blocknr_t), GFP_NOFS); /* First we compose a key to point at the writing position, we want to do that outside of any locking region. */ make_cpu_key (&key, inode, pos+1, TYPE_ANY, 3/*key length*/); /* If we came here, it means we absolutely need to open a transaction, since we need to allocate some blocks */ reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that. journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1); // Wish I know if this number enough reiserfs_update_inode_transaction(inode) ; /* Look for the in-tree position of our write, need path for block allocator */ res = search_for_position_by_key(inode->i_sb, &key, &path); if ( res == IO_ERROR ) { res = -EIO; goto error_exit; } /* Allocate blocks */ /* First fill in "hint" structure for block allocator */ hint.th = th; // transaction handle. hint.path = &path; // Path, so that block allocator can determine packing locality or whatever it needs to determine. hint.inode = inode; // Inode is needed by block allocator too. hint.search_start = 0; // We have no hint on where to search free blocks for block allocator. hint.key = key.on_disk_key; // on disk key of file. hint.block = inode->i_blocks>>(inode->i_sb->s_blocksize_bits-9); // Number of disk blocks this file occupies already. hint.formatted_node = 0; // We are allocating blocks for unformatted node. hint.preallocate = will_prealloc; /* Call block allocator to allocate blocks */ res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate); if ( res != CARRY_ON ) { if ( res == NO_DISK_SPACE ) { /* We flush the transaction in case of no space. This way some blocks might become free */ SB_JOURNAL(inode->i_sb)->j_must_wait = 1; restart_transaction(th, inode, &path); /* We might have scheduled, so search again */ res = search_for_position_by_key(inode->i_sb, &key, &path); if ( res == IO_ERROR ) { res = -EIO; goto error_exit; } /* update changed info for hint structure. */ res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate); if ( res != CARRY_ON ) { res = -ENOSPC; pathrelse(&path); goto error_exit; } } else { res = -ENOSPC; pathrelse(&path); goto error_exit; } } #ifdef __BIG_ENDIAN // Too bad, I have not found any way to convert a given region from // cpu format to little endian format { int i; for ( i = 0; i < blocks_to_allocate ; i++) allocated_blocks[i]=cpu_to_le32(allocated_blocks[i]); } #endif /* Blocks allocating well might have scheduled and tree might have changed, let's search the tree again */ /* find where in the tree our write should go */ res = search_for_position_by_key(inode->i_sb, &key, &path); if ( res == IO_ERROR ) { res = -EIO; goto error_exit_free_blocks; } bh = get_last_bh( &path ); // Get a bufferhead for last element in path. ih = get_ih( &path ); // Get a pointer to last item head in path. item = get_item( &path ); // Get a pointer to last item in path /* Let's see what we have found */ if ( res != POSITION_FOUND ) { /* position not found, this means that we might need to append file with holes first */ // Since we are writing past the file's end, we need to find out if // there is a hole that needs to be inserted before our writing // position, and how many blocks it is going to cover (we need to // populate pointers to file blocks representing the hole with zeros) { int item_offset = 1; /* * if ih is stat data, its offset is 0 and we don't want to * add 1 to pos in the hole_size calculation */ if (is_statdata_le_ih(ih)) item_offset = 0; hole_size = (pos + item_offset - (le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize))) >> inode->i_sb->s_blocksize_bits; }