- /* 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.
- res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS); // Wish I know if this number enough
- if (res)
- goto error_exit;
- 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;
- res = restart_transaction(th, inode, &path);
- if (res)
- goto error_exit;
-
- /* 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;
- }
-
- if ( hole_size > 0 ) {
- int to_paste = min_t(__u64, hole_size, MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE ); // How much data to insert first time.
- /* area filled with zeroes, to supply as list of zero blocknumbers
- We allocate it outside of loop just in case loop would spin for
- several iterations. */
- char *zeros = kmalloc(to_paste*UNFM_P_SIZE, GFP_ATOMIC); // We cannot insert more than MAX_ITEM_LEN bytes anyway.
- if ( !zeros ) {
- res = -ENOMEM;
- goto error_exit_free_blocks;
- }
- memset ( zeros, 0, to_paste*UNFM_P_SIZE);
- do {
- to_paste = min_t(__u64, hole_size, MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE );
- if ( is_indirect_le_ih(ih) ) {
- /* Ok, there is existing indirect item already. Need to append it */
- /* Calculate position past inserted item */
- make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
- res = reiserfs_paste_into_item( th, &path, &key, inode, (char *)zeros, UNFM_P_SIZE*to_paste);
- if ( res ) {
- kfree(zeros);
- goto error_exit_free_blocks;
- }
- } else if ( is_statdata_le_ih(ih) ) {
- /* No existing item, create it */
- /* item head for new item */
- struct item_head ins_ih;
-
- /* create a key for our new item */
- make_cpu_key( &key, inode, 1, TYPE_INDIRECT, 3);
-
- /* Create new item head for our new item */
- make_le_item_head (&ins_ih, &key, key.version, 1,
- TYPE_INDIRECT, to_paste*UNFM_P_SIZE,
- 0 /* free space */);
-
- /* Find where such item should live in the tree */
- res = search_item (inode->i_sb, &key, &path);
- if ( res != ITEM_NOT_FOUND ) {
- /* item should not exist, otherwise we have error */
- if ( res != -ENOSPC ) {
- reiserfs_warning (inode->i_sb,
- "green-9008: search_by_key (%K) returned %d",
- &key, res);
- }
- res = -EIO;
- kfree(zeros);
- goto error_exit_free_blocks;
- }
- res = reiserfs_insert_item( th, &path, &key, &ins_ih, inode, (char *)zeros);
- } else {
- reiserfs_panic(inode->i_sb, "green-9011: Unexpected key type %K\n", &key);
- }
- if ( res ) {
- kfree(zeros);
- goto error_exit_free_blocks;
- }
- /* Now we want to check if transaction is too full, and if it is
- we restart it. This will also free the path. */
- if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
- res = restart_transaction(th, inode, &path);
- if (res) {
- pathrelse (&path);
- kfree(zeros);
- goto error_exit;
- }
- }
-
- /* Well, need to recalculate path and stuff */
- set_cpu_key_k_offset( &key, cpu_key_k_offset(&key) + (to_paste << inode->i_blkbits));
- res = search_for_position_by_key(inode->i_sb, &key, &path);
- if ( res == IO_ERROR ) {
- res = -EIO;
- kfree(zeros);
- goto error_exit_free_blocks;
- }
- bh=get_last_bh(&path);
- ih=get_ih(&path);
- item = get_item(&path);
- hole_size -= to_paste;
- } while ( hole_size );
- kfree(zeros);
- }
- }
-
- // Go through existing indirect items first
- // replace all zeroes with blocknumbers from list
- // Note that if no corresponding item was found, by previous search,
- // it means there are no existing in-tree representation for file area
- // we are going to overwrite, so there is nothing to scan through for holes.
- for ( curr_block = 0, itempos = path.pos_in_item ; curr_block < blocks_to_allocate && res == POSITION_FOUND ; ) {
-retry:
-
- if ( itempos >= ih_item_len(ih)/UNFM_P_SIZE ) {
- /* We run out of data in this indirect item, let's look for another
- one. */
- /* First if we are already modifying current item, log it */
- if ( modifying_this_item ) {
- journal_mark_dirty (th, inode->i_sb, bh);
- modifying_this_item = 0;
- }
- /* Then set the key to look for a new indirect item (offset of old
- item is added to old item length */
- set_cpu_key_k_offset( &key, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize));
- /* Search ofor position of new key in the tree. */
- 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);
- ih=get_ih(&path);
- item = get_item(&path);
- itempos = path.pos_in_item;
- continue; // loop to check all kinds of conditions and so on.
- }
- /* Ok, we have correct position in item now, so let's see if it is
- representing file hole (blocknumber is zero) and fill it if needed */
- if ( !item[itempos] ) {
- /* Ok, a hole. Now we need to check if we already prepared this
- block to be journaled */
- while ( !modifying_this_item ) { // loop until succeed
- /* Well, this item is not journaled yet, so we must prepare
- it for journal first, before we can change it */
- struct item_head tmp_ih; // We copy item head of found item,
- // here to detect if fs changed under
- // us while we were preparing for
- // journal.
- int fs_gen; // We store fs generation here to find if someone
- // changes fs under our feet
-
- copy_item_head (&tmp_ih, ih); // Remember itemhead
- fs_gen = get_generation (inode->i_sb); // remember fs generation
- reiserfs_prepare_for_journal(inode->i_sb, bh, 1); // Prepare a buffer within which indirect item is stored for changing.
- if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
- // Sigh, fs was changed under us, we need to look for new
- // location of item we are working with
-
- /* unmark prepaerd area as journaled and search for it's
- new position */
- reiserfs_restore_prepared_buffer(inode->i_sb, bh);
- 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);
- ih=get_ih(&path);
- item = get_item(&path);
- itempos = path.pos_in_item;
- goto retry;
- }
- modifying_this_item = 1;
- }
- item[itempos] = allocated_blocks[curr_block]; // Assign new block
- curr_block++;
- }
- itempos++;
- }
-
- if ( modifying_this_item ) { // We need to log last-accessed block, if it
- // was modified, but not logged yet.
- journal_mark_dirty (th, inode->i_sb, bh);
- }
-
- if ( curr_block < blocks_to_allocate ) {
- // Oh, well need to append to indirect item, or to create indirect item
- // if there weren't any
- if ( is_indirect_le_ih(ih) ) {
- // Existing indirect item - append. First calculate key for append
- // position. We do not need to recalculate path as it should
- // already point to correct place.
- make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
- res = reiserfs_paste_into_item( th, &path, &key, inode, (char *)(allocated_blocks+curr_block), UNFM_P_SIZE*(blocks_to_allocate-curr_block));
- if ( res ) {
- goto error_exit_free_blocks;
- }
- } else if (is_statdata_le_ih(ih) ) {
- // Last found item was statdata. That means we need to create indirect item.
- struct item_head ins_ih; /* itemhead for new item */
-
- /* create a key for our new item */
- make_cpu_key( &key, inode, 1, TYPE_INDIRECT, 3); // Position one,
- // because that's
- // where first
- // indirect item
- // begins
- /* Create new item head for our new item */
- make_le_item_head (&ins_ih, &key, key.version, 1, TYPE_INDIRECT,
- (blocks_to_allocate-curr_block)*UNFM_P_SIZE,
- 0 /* free space */);
- /* Find where such item should live in the tree */
- res = search_item (inode->i_sb, &key, &path);
- if ( res != ITEM_NOT_FOUND ) {
- /* Well, if we have found such item already, or some error
- occured, we need to warn user and return error */
- if ( res != -ENOSPC ) {
- reiserfs_warning (inode->i_sb,
- "green-9009: search_by_key (%K) "
- "returned %d", &key, res);