Re: extents in e2fsprogs

Alexandre Ratchov <[email protected]>
Newsgroups gmane.comp.file-systems.ext2.devel
Message-ID <[email protected]>
hi,

thanks for your suggestions, i've updated accordingly the patch (see below).

On Wed, Jun 14, 2006 at 11:23:48AM -0600, Andreas Dilger wrote:
> On Jun 14, 2006  18:19 +0200, Alexandre Ratchov wrote:
> > +static int block_iterate_extents(struct ext3_extent_header *eh, ext2_filsys fs,
> > +				 struct block_context *ctx)
> > +{
> > +        if(eh->eh_depth == 0) {
> > +                show_extent(eh);
> > +                ex = EXT_FIRST_EXTENT(eh);
> > +                for (i = 0; i < eh->eh_entries; i++, ex++) {
> > +                        for(j=0; j< ex->ee_len; j++) {
> > +                                block_address = ex->ee_start + j;
> > +				ret = (*ctx->func)(ctx->fs, &block_address,
> > +						   (ex->ee_block + j), 0,
> > +						   i, ctx->priv_data);
> 
> One of the CFS fixes is to handle partial iteration correctly:
> 
>                                 if (ret & BLOCK_ABORT)
> 					return ret;

ok

> 
> > +                        }
> > +                }
> > +        } else {
> > +		show_index(eh);
> > +                ret = ext2fs_get_mem(fs->blocksize, &block_buf);
> > +                if (ret)
> > +                        return ret;
> > +                ix = EXT_FIRST_INDEX(eh);
> > +                for (i = 0; i < eh->eh_entries; i++, ix++) {
> > +			block_address = ix->ei_leaf;
> 
> Don't iterate over index blocks:
> 
>                         if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
>                             !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
> 

ok

> > +				ret = (*ctx->func)(ctx->fs, &block_address,
> > +					   BLOCK_COUNT_IND, 0, i, ctx->priv_data);
> > +				if (ret & BLOCK_ABORT) {
> > +					ext2fs_free_mem(&block_buf);
> > +					return ret;
> > +				}
> 			}
> 
> > @@ -83,10 +84,26 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, e
> >  	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
> >  	inode.i_uid = inode.i_gid = 0;
> >  	inode.i_blocks = fs->blocksize / 512;
> > -	inode.i_block[0] = blk;
> >  	inode.i_links_count = 2;
> >  	inode.i_ctime = inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(NULL);
> >  	inode.i_size = fs->blocksize;
> > +	if (fs->super->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_64BIT) {
> > +		struct ext3_extent_header *eh = (struct ext3_extent_header *)inode.i_block;
> > +		struct ext3_extent *ex = EXT_FIRST_EXTENT(eh);
> > +
> > +		 eh->eh_magic = EXT3_EXT_MAGIC;
> > +		 eh->eh_depth = 0;
> > +		 eh->eh_entries = 1;
> > +		 eh->eh_max = (sizeof(inode.i_block) - sizeof(struct ext3_extent_header))
> > +			 / sizeof(struct ext3_extent);
> > +		 ex->ee_block = 0;
> > +		 ex->ee_start = blk;
> > +		 ex->ee_len = 1;
> > +
> > +		 inode.i_flags = EXT3_EXTENTS_FL;
> > +	} else {
> > +		inode.i_block[0] = blk;
> > +	}
> 
> This relates to 64-bit support...
> 

the EXT2_FEATURE_RO_COMPAT_64BIT flag is wrong;

however, if the file system is using extents then we can create the new
directory using extents; is it ok?

> > Index: e2fsprogs-1.39/e2fsck/pass1.c
> > ===================================================================
> > --- e2fsprogs-1.39.orig/e2fsck/pass1.c	2006-05-31 15:44:49.000000000 +0200
> > +++ e2fsprogs-1.39/e2fsck/pass1.c	2006-06-14 13:25:47.000000000 +0200
> > @@ -806,21 +806,30 @@ void e2fsck_pass1(e2fsck_t ctx)
> >  			ctx->fs_sockets_count++;
> >  		} else
> >  			mark_inode_bad(ctx, ino);
> > -		if (inode->i_block[EXT2_IND_BLOCK])
> > -			ctx->fs_ind_count++;
> > -		if (inode->i_block[EXT2_DIND_BLOCK])
> > -			ctx->fs_dind_count++;
> > -		if (inode->i_block[EXT2_TIND_BLOCK])
> > -			ctx->fs_tind_count++;
> > -		if (inode->i_block[EXT2_IND_BLOCK] ||
> > -		    inode->i_block[EXT2_DIND_BLOCK] ||
> > -		    inode->i_block[EXT2_TIND_BLOCK] ||
> > -		    inode->i_file_acl) {
> > +		if (fs->super->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_64BIT) {
> > +		    if (inode->i_flags & EXT3_EXTENTS_FL) {
> >  			inodes_to_process[process_inode_count].ino = ino;
> >  			inodes_to_process[process_inode_count].inode = *inode;
> >  			process_inode_count++;
> > +		    } else
> > +			    mark_inode_bad(ctx, ino);
> 
> Also related to 64-bit support...
> 
> > +		} else {
> > +			if (inode->i_block[EXT2_IND_BLOCK])
> > +				ctx->fs_ind_count++;
> > +			if (inode->i_block[EXT2_DIND_BLOCK])
> > +				ctx->fs_dind_count++;
> > +			if (inode->i_block[EXT2_TIND_BLOCK])
> > +				ctx->fs_tind_count++;
> 
> These stats could use the ext3_extent_hdr depth to account similar
> stats for extents.
> 
> > +			if (inode->i_block[EXT2_IND_BLOCK] ||
> > +			    inode->i_block[EXT2_DIND_BLOCK] ||
> > +			    inode->i_block[EXT2_TIND_BLOCK] ||
> > +			    inode->i_file_acl) {
> > +				inodes_to_process[process_inode_count].ino = ino;
> > +				inodes_to_process[process_inode_count].inode = *inode;
> > +				process_inode_count++;
> 
> This probably needs to also check the extent_hdr depth for processing...
> 

ok, fixed the above in the way you suggested; also fixed
ext2fs_inode_has_valid_blocks(), see the attached patch.

-- 
Alexandre

Index: e2fsck/Makefile.in
===================================================================
RCS file: /home/ratchova/cvs/e2fsprogs/e2fsck/Makefile.in,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- e2fsck/Makefile.in	15 Jun 2006 13:44:32 -0000	1.1.1.1
+++ e2fsck/Makefile.in	15 Jun 2006 18:11:58 -0000	1.1.1.1.2.1
@@ -261,6 +261,7 @@ super.o: $(srcdir)/super.c $(top_srcdir)
 pass1.o: $(srcdir)/pass1.c $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h \
  $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(top_srcdir)/lib/blkid/blkid.h $(top_builddir)/lib/blkid/blkid_types.h \
Index: e2fsck/pass1.c
===================================================================
RCS file: /home/ratchova/cvs/e2fsprogs/e2fsck/pass1.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- e2fsck/pass1.c	15 Jun 2006 13:44:32 -0000	1.1.1.1
+++ e2fsck/pass1.c	15 Jun 2006 18:11:58 -0000	1.1.1.1.2.1
@@ -46,6 +46,7 @@
 
 #include "e2fsck.h"
 #include <ext2fs/ext2_ext_attr.h>
+#include <ext2fs/ext3_extents.h>
 
 #include "problem.h"
 
@@ -392,6 +393,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 	int		imagic_fs;
 	int		busted_fs_time = 0;
 	int		inode_size;
+	struct ext3_extent_header *eh;
 	
 #ifdef RESOURCE_TRACK
 	init_resource_track(&rtrack);
@@ -793,8 +795,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 				check_blocks(ctx, &pctx, block_buf);
 				continue;
 			}
-		}
-		else if (LINUX_S_ISFIFO (inode->i_mode) &&
+		} else if (LINUX_S_ISFIFO (inode->i_mode) &&
 			 e2fsck_pass1_check_device_inode(fs, inode)) {
 			check_immutable(ctx, &pctx);
 			check_size(ctx, &pctx);
@@ -806,21 +807,46 @@ void e2fsck_pass1(e2fsck_t ctx)
 			ctx->fs_sockets_count++;
 		} else
 			mark_inode_bad(ctx, ino);
-		if (inode->i_block[EXT2_IND_BLOCK])
-			ctx->fs_ind_count++;
-		if (inode->i_block[EXT2_DIND_BLOCK])
-			ctx->fs_dind_count++;
-		if (inode->i_block[EXT2_TIND_BLOCK])
-			ctx->fs_tind_count++;
-		if (inode->i_block[EXT2_IND_BLOCK] ||
-		    inode->i_block[EXT2_DIND_BLOCK] ||
-		    inode->i_block[EXT2_TIND_BLOCK] ||
-		    inode->i_file_acl) {
-			inodes_to_process[process_inode_count].ino = ino;
-			inodes_to_process[process_inode_count].inode = *inode;
-			process_inode_count++;
-		} else
-			check_blocks(ctx, &pctx, block_buf);
+			
+		if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS &&
+		    inode->i_flags & EXT3_EXTENTS_FL) {
+			eh = (struct ext3_extent_header *)inode->i_block;
+			switch(eh->eh_depth) {
+			case 0:
+				break;
+			case 1: 
+				ctx->fs_ind_count++;
+				break;
+			case 2:	
+				ctx->fs_dind_count++;
+				break;
+			default:
+				ctx->fs_tind_count++;
+				break;
+			}
+			if (eh->eh_depth > 0) {
+				inodes_to_process[process_inode_count].ino = ino;
+				inodes_to_process[process_inode_count].inode = *inode;
+				process_inode_count++;
+			} else 
+				check_blocks(ctx, &pctx, block_buf);
+		} else {
+			if (inode->i_block[EXT2_IND_BLOCK])
+				ctx->fs_ind_count++;
+			if (inode->i_block[EXT2_DIND_BLOCK])
+				ctx->fs_dind_count++;
+			if (inode->i_block[EXT2_TIND_BLOCK])
+				ctx->fs_tind_count++;
+			if (inode->i_block[EXT2_IND_BLOCK] ||
+			    inode->i_block[EXT2_DIND_BLOCK] ||
+			    inode->i_block[EXT2_TIND_BLOCK] ||
+			    inode->i_file_acl) {
+				inodes_to_process[process_inode_count].ino = ino;
+				inodes_to_process[process_inode_count].inode = *inode;
+				process_inode_count++;
+			} else
+				check_blocks(ctx, &pctx, block_buf);
+		}
 
 		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
 			return;
Index: lib/ext2fs/Makefile.in
===================================================================
RCS file: /home/ratchova/cvs/e2fsprogs/lib/ext2fs/Makefile.in,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- lib/ext2fs/Makefile.in	15 Jun 2006 13:44:32 -0000	1.1.1.1
+++ lib/ext2fs/Makefile.in	15 Jun 2006 18:12:01 -0000	1.1.1.1.2.1
@@ -516,6 +516,7 @@ unlink.o: $(srcdir)/unlink.c $(srcdir)/e
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
 valid_blk.o: $(srcdir)/valid_blk.c $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext3_extents.h \
  $(srcdir)/ext2_fs.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
 version.o: $(srcdir)/version.c $(srcdir)/ext2_fs.h \
Index: lib/ext2fs/block.c
===================================================================
RCS file: /home/ratchova/cvs/e2fsprogs/lib/ext2fs/block.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- lib/ext2fs/block.c	15 Jun 2006 13:44:32 -0000	1.1.1.1
+++ lib/ext2fs/block.c	15 Jun 2006 18:12:01 -0000	1.1.1.1.2.1
@@ -17,6 +17,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext3_extents.h"
 
 struct block_context {
 	ext2_filsys	fs;
@@ -36,6 +37,110 @@ struct block_context {
 	void	*priv_data;
 };
 
+#define DEBUG_EXT 0
+
+#if DEBUG_EXT
+void show_header(struct ext3_extent_header *eh)
+{
+        printf("header: magic=%x, entries=%d, max=%d, depth=%d, generation=%d,",
+	       eh->eh_magic, eh->eh_entries, eh->eh_max, eh->eh_depth,
+	       eh->eh_generation);
+}
+
+void show_index(struct ext3_extent_header *eh)
+{
+        struct ext3_extent_idx *ix;
+        int i;
+
+        ix = EXT_FIRST_INDEX(eh);
+        printf("this node has %d indexs\n",eh->e_num);
+        for (i = 0; i < eh->eh_entries; i++, ix++) {
+                printf("index %d, block = %d, leaf = %d\n", i,
+		       ix->ei_block, ix->ei_leaf);
+        }
+}
+
+void show_extent(struct ext3_extent_header *eh)
+{
+        struct ext3_extent *ex;
+        int i;
+
+        ex = EXT_FIRST_EXTENT(eh);
+        printf("this node has %d extents\n", eh->e_len);
+}
+#else
+#define show_header(eh) do { } while (0)
+#define show_index(eh) do { } while (0)
+#define show_extent(eh) do { } while (0)
+#endif
+
+static int block_iterate_extents(struct ext3_extent_header *eh, ext2_filsys fs,
+				 struct block_context *ctx)
+{
+        int ret = 0;
+        int i,j;
+        char * block_buf;
+        blk_t  block_address;
+        struct ext3_extent *ex;
+        struct ext3_extent_idx *ix;
+        struct ext3_extent_header *nh;
+
+        if(eh->eh_depth == 0) {
+                show_extent(eh);
+                ex = EXT_FIRST_EXTENT(eh);
+                for (i = 0; i < eh->eh_entries; i++, ex++) {
+                        for(j=0; j< ex->ee_len; j++) {
+                                block_address = ex->ee_start + j;
+				ret = (*ctx->func)(ctx->fs, &block_address,
+						   (ex->ee_block + j), 0,
+						   i, ctx->priv_data);
+				if (ret & BLOCK_ABORT)
+					return ret;
+                        }
+                }
+        } else {
+		show_index(eh);
+                ret = ext2fs_get_mem(fs->blocksize, &block_buf);
+                if (ret)
+                        return ret;
+                ix = EXT_FIRST_INDEX(eh);
+                for (i = 0; i < eh->eh_entries; i++, ix++) {
+			block_address = ix->ei_leaf;
+			if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+			    !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
+				ret = (*ctx->func)(ctx->fs, &block_address,
+						   BLOCK_COUNT_IND, 0, i, ctx->priv_data);
+				if (ret & BLOCK_ABORT) {
+					ext2fs_free_mem(&block_buf);
+					return ret;
+				}
+			}
+			ctx->errcode = io_channel_read_blk(ctx->fs->io,
+							   ix->ei_leaf, 1,
+							   block_buf);
+			if(ctx->errcode) {
+				ret |= BLOCK_ERROR;
+				ext2fs_free_mem(&block_buf);
+				return ret;
+			}
+			nh = (struct ext3_extent_header *)block_buf;
+			show_header(nh);
+			if (nh->eh_magic != EXT3_EXT_MAGIC)
+			{
+				ret |= BLOCK_ERROR;
+				ext2fs_free_mem(&block_buf);
+				return ret;
+			}
+			ret = block_iterate_extents(nh, fs, ctx);
+			/* 
+			 * XXX: have to check ret for BLOCK_ERROR and return it ? 
+			 */
+		}
+		ext2fs_free_mem(&block_buf);
+	}
+	return ret;
+}
+
 static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
 			     int ref_offset, struct block_context *ctx)
 {
@@ -283,6 +388,7 @@ errcode_t ext2fs_block_iterate2(ext2_fil
 	errcode_t	retval;
 	struct block_context ctx;
 	int	limit;
+	struct ext3_extent_header *eh;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -338,7 +444,23 @@ errcode_t ext2fs_block_iterate2(ext2_fil
 				goto abort_exit;
 		}
 	}
-	
+
+	/*
+	 * Iterate over normal data blocks with extents
+	 */
+        ext2fs_read_inode(fs, ino, &inode);
+        if (inode.i_flags & EXT3_EXTENTS_FL) {
+                eh = (struct ext3_extent_header *)&inode.i_block[0];
+                if (eh->eh_magic == EXT3_EXT_MAGIC) {
+		        show_header(eh);
+                        ret = block_iterate_extents(eh, fs, &ctx);
+                        goto abort_exit;
+                } else {
+                        inode.i_flags &= ~(EXT3_EXTENTS_FL);
+                        ext2fs_write_inode(fs, ino, &inode);
+                }
+        }
+
 	/*
 	 * Iterate over normal data blocks
 	 */
Index: lib/ext2fs/bmap.c
===================================================================
RCS file: /home/ratchova/cvs/e2fsprogs/lib/ext2fs/bmap.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- lib/ext2fs/bmap.c	15 Jun 2006 13:44:32 -0000	1.1.1.1
+++ lib/ext2fs/bmap.c	15 Jun 2006 18:12:01 -0000	1.1.1.1.2.1
@@ -17,6 +17,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext3_extents.h"
 
 #if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
 #define _BMAP_INLINE_	__inline__
@@ -31,6 +32,49 @@ extern errcode_t ext2fs_bmap(ext2_filsys
 
 #define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
 
+static int block_extents_bmap(struct ext3_extent_header *eh, ext2_filsys fs,
+			      blk_t block, blk_t *phys_blk)
+{
+	int ret = 0;
+	int i;
+	char * block_buf;
+	struct ext3_extent *ex;
+	struct ext3_extent_idx *ix;
+	struct ext3_extent_header *nh;
+
+	if(eh->eh_depth == 0) {
+		ex = EXT_FIRST_EXTENT(eh);
+		for (i = 0; i < eh->eh_entries; i++, ex++)
+			if ( (ex->ee_block <= block) && (block < ex->ee_block +  ex->ee_len) ) {
+				*phys_blk = ex->ee_start + (block - ex->ee_block);
+				return 0;
+			}
+		return BLOCK_ERROR;
+	} else {
+		ret = ext2fs_get_mem(fs->blocksize, &block_buf);
+		if (ret)
+			return ret;
+		ix = EXT_FIRST_INDEX(eh);
+		for (i = 0; i < eh->eh_entries; i++, ix++) {
+			ret = io_channel_read_blk(fs->io,
+						  ix->ei_leaf, 1,
+						  block_buf);
+			if (ret) {
+				ext2fs_free_mem(&block_buf);
+				return BLOCK_ERROR;
+			}
+			nh = (struct ext3_extent_header *)block_buf;
+			if (nh->eh_magic != EXT3_EXT_MAGIC) {
+				ext2fs_free_mem(&block_buf);
+				return BLOCK_ERROR;
+			}
+			ret = block_extents_bmap(nh, fs, block, phys_blk);
+		}
+		ext2fs_free_mem(&block_buf);
+	}
+	return ret;
+}
+
 static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags, 
 					      blk_t ind, char *block_buf, 
 					      int *blocks_alloc,
@@ -144,6 +188,7 @@ errcode_t ext2fs_bmap(ext2_filsys fs, ex
 	char	*buf = 0;
 	errcode_t	retval = 0;
 	int		blocks_alloc = 0, inode_dirty = 0;
+	struct ext3_extent_header * eh;
 
 	if (!(bmap_flags & BMAP_SET))
 		*phys_blk = 0;
@@ -155,6 +200,15 @@ errcode_t ext2fs_bmap(ext2_filsys fs, ex
 			return retval;
 		inode = &inode_buf;
 	}
+
+	if (inode->i_flags & EXT3_EXTENTS_FL) {
+		eh = (struct ext3_extent_header *)&inode->i_block[0];
+		if (eh->eh_magic == EXT3_EXT_MAGIC)
+			return block_extents_bmap(eh, fs, block, phys_blk);
+		else
+			return BLOCK_ERROR;
+	}
+
 	addr_per_block = (blk_t) fs->blocksize >> 2;
 
 	if (!block_buf) {
Index: lib/ext2fs/ext2fs.h
===================================================================
RCS file: /home/ratchova/cvs/e2fsprogs/lib/ext2fs/ext2fs.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- lib/ext2fs/ext2fs.h	15 Jun 2006 13:44:32 -0000	1.1.1.1
+++ lib/ext2fs/ext2fs.h	15 Jun 2006 18:12:01 -0000	1.1.1.1.2.1
@@ -453,12 +453,14 @@ typedef struct ext2_icount *ext2_icount_
 					 EXT2_FEATURE_INCOMPAT_COMPRESSION|\
 					 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
 					 EXT2_FEATURE_INCOMPAT_META_BG|\
-					 EXT3_FEATURE_INCOMPAT_RECOVER)
+					 EXT3_FEATURE_INCOMPAT_RECOVER|\
+					 EXT3_FEATURE_INCOMPAT_EXTENTS)
 #else
 #define EXT2_LIB_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE|\
 					 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
 					 EXT2_FEATURE_INCOMPAT_META_BG|\
-					 EXT3_FEATURE_INCOMPAT_RECOVER)
+					 EXT3_FEATURE_INCOMPAT_RECOVER|\
+					 EXT3_FEATURE_INCOMPAT_EXTENTS)
 #endif
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
Index: lib/ext2fs/ext3_extents.h
===================================================================
RCS file: lib/ext2fs/ext3_extents.h
diff -N lib/ext2fs/ext3_extents.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/ext2fs/ext3_extents.h	15 Jun 2006 18:17:03 -0000	1.1.2.1
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2003,2004 Cluster File Systems, Inc, [email protected]
+ * Written by Alex Tomas <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
+ */
+
+#ifndef _LINUX_EXT3_EXTENTS
+#define _LINUX_EXT3_EXTENTS
+
+/*
+ * with AGRESSIVE_TEST defined capacity of index/leaf blocks
+ * become very little, so index split, in-depth growing and
+ * other hard changes happens much more often
+ * this is for debug purposes only
+ */
+#define AGRESSIVE_TEST_
+
+/*
+ * if CHECK_BINSEARCH defined, then results of binary search
+ * will be checked by linear search
+ */
+#define CHECK_BINSEARCH_
+
+/*
+ * if EXT_DEBUG is defined you can use 'extdebug' mount option
+ * to get lots of info what's going on
+ */
+#define EXT_DEBUG
+#ifdef EXT_DEBUG
+#define ext_debug(tree,fmt,a...) 			\
+do {							\
+	if (test_opt((tree)->inode->i_sb, EXTDEBUG))	\
+		printk(fmt, ##a);			\
+} while (0);
+#else
+#define ext_debug(tree,fmt,a...)
+#endif
+
+/*
+ * if EXT_STATS is defined then stats numbers are collected
+ * these number will be displayed at umount time
+ */
+#define EXT_STATS_
+
+
+#define EXT3_ALLOC_NEEDED	3	/* block bitmap + group desc. + sb */
+
+/*
+ * ext3_inode has i_block array (total 60 bytes)
+ * first 4 bytes are used to store:
+ *  - tree depth (0 mean there is no tree yet. all extents in the inode)
+ *  - number of alive extents in the inode
+ */
+
+/*
+ * this is extent on-disk structure
+ * it's used at the bottom of the tree
+ */
+struct ext3_extent {
+	__u32	ee_block;	/* first logical block extent covers */
+	__u16	ee_len;		/* number of blocks covered by extent */
+	__u16	ee_start_hi;	/* high 16 bits of physical block */
+	__u32	ee_start;	/* low 32 bigs of physical block */
+};
+
+/*
+ * this is index on-disk structure
+ * it's used at all the levels, but the bottom
+ */
+struct ext3_extent_idx {
+	__u32	ei_block;	/* index covers logical blocks from 'block' */
+	__u32	ei_leaf;	/* pointer to the physical block of the next *
+				 * level. leaf or next index could bet here */
+	__u16	ei_leaf_hi;	/* high 16 bits of physical block */
+	__u16	ei_unused;
+};
+
+/*
+ * each block (leaves and indexes), even inode-stored has header
+ */
+struct ext3_extent_header {
+	__u16	eh_magic;	/* probably will support different formats */
+	__u16	eh_entries;	/* number of valid entries */
+	__u16	eh_max;		/* capacity of store in entries */
+	__u16	eh_depth;	/* has tree real underlaying blocks? */
+	__u32	eh_generation;	/* generation of the tree */
+};
+
+#define EXT3_EXT_MAGIC		0xf30a
+
+/*
+ * array of ext3_ext_path contains path to some extent
+ * creation/lookup routines use it for traversal/splitting/etc
+ * truncate uses it to simulate recursive walking
+ */
+struct ext3_ext_path {
+	__u32				p_block;
+	__u16				p_depth;
+	struct ext3_extent		*p_ext;
+	struct ext3_extent_idx		*p_idx;
+	struct ext3_extent_header	*p_hdr;
+	struct buffer_head		*p_bh;
+};
+
+/*
+ * structure for external API
+ */
+
+#define EXT_CONTINUE	0
+#define EXT_BREAK	1
+#define EXT_REPEAT	2
+
+
+#define EXT_MAX_BLOCK	0xffffffff
+#define EXT_CACHE_MARK	0xffff
+
+
+#define EXT_FIRST_EXTENT(__hdr__) \
+	((struct ext3_extent *) (((char *) (__hdr__)) +		\
+				 sizeof(struct ext3_extent_header)))
+#define EXT_FIRST_INDEX(__hdr__) \
+	((struct ext3_extent_idx *) (((char *) (__hdr__)) +	\
+				     sizeof(struct ext3_extent_header)))
+#define EXT_HAS_FREE_INDEX(__path__) \
+	((__path__)->p_hdr->eh_entries < (__path__)->p_hdr->eh_max)
+#define EXT_LAST_EXTENT(__hdr__) \
+	(EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->eh_entries - 1)
+#define EXT_LAST_INDEX(__hdr__) \
+	(EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->eh_entries - 1)
+#define EXT_MAX_EXTENT(__hdr__) \
+	(EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->eh_max - 1)
+#define EXT_MAX_INDEX(__hdr__) \
+	(EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->eh_max - 1)
+
+#define EXT_ROOT_HDR(tree) \
+	((struct ext3_extent_header *) (tree)->root)
+#define EXT_BLOCK_HDR(bh) \
+	((struct ext3_extent_header *) (bh)->b_data)
+#define EXT_DEPTH(_t_)	\
+	(((struct ext3_extent_header *)((_t_)->root))->eh_depth)
+#define EXT_GENERATION(_t_)	\
+	(((struct ext3_extent_header *)((_t_)->root))->eh_generation)
+
+
+#define EXT_ASSERT(__x__) if (!(__x__)) BUG();
+
+
+/*
+ * this structure is used to gather extents from the tree via ioctl
+ */
+struct ext3_extent_buf {
+	unsigned long start;
+	int buflen;
+	void *buffer;
+	void *cur;
+	int err;
+};
+
+/*
+ * this structure is used to collect stats info about the tree
+ */
+struct ext3_extent_tree_stats {
+	int depth;
+	int extents_num;
+	int leaf_num;
+};
+
+#ifdef __KERNEL__
+/*
+ * ext3_extents_tree is used to pass initial information
+ * to top-level extents API
+ */
+struct ext3_extents_helpers;
+struct ext3_extents_tree {
+	struct inode *inode;	/* inode which tree belongs to */
+	void *root;		/* ptr to data top of tree resides at */
+	void *buffer;		/* will be passed as arg to ^^ routines	*/
+	int buffer_len;
+	void *private;
+	struct ext3_extent *cex;/* last found extent */
+	struct ext3_extents_helpers *ops;
+};
+
+struct ext3_extents_helpers {
+	int (*get_write_access)(handle_t *h, void *buffer);
+	int (*mark_buffer_dirty)(handle_t *h, void *buffer);
+	int (*mergable)(struct ext3_extent *ex1, struct ext3_extent *ex2);
+	int (*remove_extent_credits)(struct ext3_extents_tree *,
+					struct ext3_extent *, unsigned long,
+					unsigned long);
+	int (*remove_extent)(struct ext3_extents_tree *,
+				struct ext3_extent *, unsigned long,
+				unsigned long);
+	int (*new_block)(handle_t *, struct ext3_extents_tree *,
+				struct ext3_ext_path *, struct ext3_extent *,
+				int *);
+};
+
+/*
+ * to be called by ext3_ext_walk_space()
+ * negative retcode - error
+ * positive retcode - signal for ext3_ext_walk_space(), see below
+ * callback must return valid extent (passed or newly created)
+ */
+typedef int (*ext_prepare_callback)(struct ext3_extents_tree *,
+					struct ext3_ext_path *,
+					struct ext3_extent *, int);
+void ext3_init_tree_desc(struct ext3_extents_tree *, struct inode *);
+extern int ext3_extent_tree_init(handle_t *, struct ext3_extents_tree *);
+extern int ext3_ext_calc_credits_for_insert(struct ext3_extents_tree *, struct ext3_ext_path *);
+extern int ext3_ext_insert_extent(handle_t *, struct ext3_extents_tree *, struct ext3_ext_path *, struct ext3_extent *);
+extern int ext3_ext_walk_space(struct ext3_extents_tree *, unsigned long, unsigned long, ext_prepare_callback);
+extern int ext3_ext_remove_space(struct ext3_extents_tree *, unsigned long, unsigned long);
+extern struct ext3_ext_path * ext3_ext_find_extent(struct ext3_extents_tree *, int, struct ext3_ext_path *);
+
+static inline void
+ext3_ext_invalidate_cache(struct ext3_extents_tree *tree)
+{
+	if (tree->cex)
+		tree->cex->ee_len = 0;
+}
+#endif /* __KERNEL__ */
+
+
+#endif /* _LINUX_EXT3_EXTENTS */
+
Index: lib/ext2fs/mkdir.c
===================================================================
RCS file: /home/ratchova/cvs/e2fsprogs/lib/ext2fs/mkdir.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- lib/ext2fs/mkdir.c	15 Jun 2006 13:44:32 -0000	1.1.1.1
+++ lib/ext2fs/mkdir.c	15 Jun 2006 18:12:01 -0000	1.1.1.1.2.1
@@ -25,6 +25,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext3_extents.h"
 
 #ifndef EXT2_FT_DIR
 #define EXT2_FT_DIR		2
@@ -83,10 +84,29 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, e
 	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
 	inode.i_uid = inode.i_gid = 0;
 	inode.i_blocks = fs->blocksize / 512;
-	inode.i_block[0] = blk;
 	inode.i_links_count = 2;
 	inode.i_ctime = inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(NULL);
 	inode.i_size = fs->blocksize;
+	/*
+	 * if extents are enabled, create the directory using extents map
+	 */
+	if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
+		struct ext3_extent_header *eh = (struct ext3_extent_header *)inode.i_block;
+		struct ext3_extent *ex = EXT_FIRST_EXTENT(eh);
+
+		 eh->eh_magic = EXT3_EXT_MAGIC;
+		 eh->eh_depth = 0;
+		 eh->eh_entries = 1;
+		 eh->eh_max = (sizeof(inode.i_block) - sizeof(struct ext3_extent_header))
+			 / sizeof(struct ext3_extent);
+		 ex->ee_block = 0;
+		 ex->ee_start = blk;
+		 ex->ee_len = 1;
+
+		 inode.i_flags = EXT3_EXTENTS_FL;
+	} else {
+		inode.i_block[0] = blk;
+	}
 
 	/*
 	 * Write out the inode and inode data block
Index: lib/ext2fs/valid_blk.c
===================================================================
RCS file: /home/ratchova/cvs/e2fsprogs/lib/ext2fs/valid_blk.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- lib/ext2fs/valid_blk.c	15 Jun 2006 13:44:32 -0000	1.1.1.1
+++ lib/ext2fs/valid_blk.c	15 Jun 2006 18:12:01 -0000	1.1.1.1.2.1
@@ -19,6 +19,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext3_extents.h"
 
 /*
  * This function returns 1 if the inode's block entries actually
@@ -26,6 +27,7 @@
  */
 int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
 {
+	struct ext3_extent_header *eh;
 	/*
 	 * Only directories, regular files, and some symbolic links
 	 * have valid block entries.
@@ -41,12 +43,22 @@ int ext2fs_inode_has_valid_blocks(struct
 	if (LINUX_S_ISLNK (inode->i_mode)) {
 		if (inode->i_file_acl == 0) {
 			/* With no EA block, we can rely on i_blocks */
-			if (inode->i_blocks == 0)
-				return 0;
+			if (inode->i_flags & EXT3_EXTENTS_FL) {
+				eh = (struct ext3_extent_header *)inode->i_block;
+				if (eh->eh_entries == 0) 
+					return 0;
+			} else {
+				if (inode->i_blocks == 0)
+					return 0;
+			}
 		} else {
 			/* With an EA block, life gets more tricky */
 			if (inode->i_size >= EXT2_N_BLOCKS*4)
 				return 1; /* definitely using i_block[] */
+			/* 
+			 * we cant have EA + extents, so assume we aren't
+			 * using extents
+			 */
 			if (inode->i_size > 4 && inode->i_block[1] == 0)
 				return 1; /* definitely using i_block[] */
 			return 0; /* Probably a fast symlink */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.