On Tue, 2006-12-12 at 11:53 +0530, Amit K. Arora wrote: > Hi Mingming, > Hi Amit, > On Mon, Dec 11, 2006 at 05:28:15PM -0800, Mingming Cao wrote: > > On Wed, 2006-12-06 at 11:28 +0530, Amit K. Arora wrote: > > > > > @@ -1142,13 +1155,22 @@ > > > /* try to insert block into found extent and return */ > > > if (ex && ext4_can_extents_be_merged(inode, ex, newext)) { > > > ext_debug("append %d block to %d:%d (from %llu)\n", > > > - le16_to_cpu(newext->ee_len), > > > + ext4_ext_get_actual_len(newext), > > > le32_to_cpu(ex->ee_block), > > > - le16_to_cpu(ex->ee_len), ext_pblock(ex)); > > > + ext4_ext_get_actual_len(ex), ext_pblock(ex)); > > > if ((err = ext4_ext_get_access(handle, inode, path + depth))) > > > return err; > > > - ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len) > > > - + le16_to_cpu(newext->ee_len)); > > > + > > > + /* ext4_can_extents_be_merged should have checked that either > > > + * both extents are uninitialized, or both aren't. Thus we > > > + * need to check any of them here. > > > + */ > > > + if (ext4_ext_is_uninitialized(ex)) > > > + uninitialized = 1; > > > + ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) > > > + + ext4_ext_get_actual_len(newext)); > > Above line will "remove" the uninitialized bit from "ex", if it was set. > We call ext4_ext_get_actual_len() to get the "actual" lengths of the two > extents, which removes this MSB in ee_len (MSB in ee_len is used to mark > an extent uninitialized). Now, we do this because if lengths of two > uninitialized extents will be added as it is (i.e. without masking out > the MSB in the length), it will result in removing the MSB in ee_len. > For example, 0x8002 + 0x8003 => 0x10005 => 0x5 (since ee_len is 16 bit). > > That is why just before this line, we save the "state" of this extent, > whether it was uninitialized or not. And, we restore this "state" below. Ah...you are right:) More comments below... > Index: linux-2.6.19/fs/ext4/ioctl.c > =================================================================== > --- linux-2.6.19.orig/fs/ext4/ioctl.c 2006-12-06 10:18:12.000000000 +0530 > +++ linux-2.6.19/fs/ext4/ioctl.c 2006-12-06 10:18:15.000000000 +0530 > @@ -248,6 +248,47 @@ > return err; > } > > + case EXT4_IOC_PREALLOCATE: { > + struct ext4_falloc_input input; > + handle_t *handle; > + ext4_fsblk_t block, max_blocks; > + int ret = 0; > + struct buffer_head map_bh; > + unsigned int blkbits = inode->i_blkbits; > + > + if (IS_RDONLY(inode)) > + return -EROFS; > + > + if (copy_from_user(&input, > + (struct ext4_falloc_input __user *) arg, sizeof(input))) > + return -EFAULT; > + > + if (input.len == 0) > + return -EINVAL; > + > + if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) > + return -ENOTTY; > Supporting preallocation for extent based files seems fairly straightforward. I agree we should look at this first. After get this done, it probably worth re-consider whether to support preallocation for non-extent based files on ext4. I could imagine user upgrade from ext3 to ext4, and expecting to use preallocation on those existing files.... > + > + block = EXT4_BLOCK_ALIGN(input.offset, blkbits) >> blkbits; > + max_blocks = EXT4_BLOCK_ALIGN(input.len, blkbits) >> blkbits; > + handle=ext4_journal_start(inode, > + EXT4_DATA_TRANS_BLOCKS(inode->i_sb)+max_blocks); > + if (IS_ERR(handle)) > + return PTR_ERR(handle); > + while(ret>=0 && ret<max_blocks) > + { > + block = block + ret; > + max_blocks = max_blocks - ret; > + ret = ext4_ext_get_blocks(handle, inode, block, > + max_blocks, &map_bh, > + EXT4_CREATE_UNINITIALIZED_EXT, 1); Since the interface takes offset and number of blocks to allocate, I assuming we are going to handle holes in preallocation, thus, we cannot not mark the extend_size flag to 1 when calling ext4_ext_get_blocks. I think we should update i_size and i_disksize after preallocation. Oh, to protect parallel updating i_size, we have to take i_mutex down. > + } > + ext4_mark_inode_dirty(handle, inode); > + ext4_journal_stop(handle); > + Error code returned by ext4_journal_stop() is being ignored here, is this right? Well, there are other places in ext34/ioctl.c which ignore the return returned by ext4_journal_stop(), maybe should fix this in a separate patch. > + return ret>0?0:ret; > + } > > Oh, what if we failed to allocate the full amount of blocks? i.e, the ext4_ext_get_blocks() returns -ENOSPC error and exit the loop early. Are we going to return error, or try something like if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) goto retry I wonder it might be useful to return the actual number of blocks preallocated back to the application. Mingming - To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html