linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2 v4] dump a sparse file in debugfs
@ 2013-01-25  3:39 Zheng Liu
  2013-01-25  3:39 ` [PATCH 1/2 v4] libext2fs: introduce lseek SEEK_DATA/HOLE Zheng Liu
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Zheng Liu @ 2013-01-25  3:39 UTC (permalink / raw)
  To: linux-ext4; +Cc: Zheng Liu, Theodore Ts'o

Hi all,

This is the fourth try to support to dump a sparse file in debugfs.  In this
patch series the only change is using ext2fs_llseek() in dump_file to get a
better portability.

v4 <- v3:
 - call ext2fs_llseek() in dump_file to seek to the next data because of better
   portability

v3 <- v2:
 - use extent interfaces to handle extent-based file in seek_data/hole function
 - call ext2fs_file_llseek() to retrieve current offset in dump_file()

v2 <- v1:
 - split original patch into two parts.
 - make code clearly according to Ted's suggestions

Regards,
						- Zheng

Zheng Liu (2):
  libext2fs: introduce lseek SEEK_DATA/HOLE
  debugfs: dump a sparse file

 debugfs/dump.c            |  48 +++++++++--
 lib/ext2fs/ext2_err.et.in |   6 ++
 lib/ext2fs/ext2fs.h       |   3 +
 lib/ext2fs/fileio.c       | 208 +++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 254 insertions(+), 11 deletions(-)

-- 
1.7.12.rc2.18.g61b472e


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2 v4] libext2fs: introduce lseek SEEK_DATA/HOLE
  2013-01-25  3:39 [PATCH 0/2 v4] dump a sparse file in debugfs Zheng Liu
@ 2013-01-25  3:39 ` Zheng Liu
  2013-01-25  3:39 ` [PATCH 2/2 v4] debugfs: dump a sparse file Zheng Liu
  2013-05-13 13:33 ` [PATCH 0/2 v4] dump a sparse file in debugfs Zheng Liu
  2 siblings, 0 replies; 4+ messages in thread
From: Zheng Liu @ 2013-01-25  3:39 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

ext2fs_file_llseek is extented to introduce SEEK_DATA/HOLE.  In *_data()
function it will find the next data, and in *_hole() function it will
find the next hole.  A new error code called EXT2_ET_SEEK_BEYOND_EOF is
define to indicate that the offset is beyond the end of file.

Cc: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 lib/ext2fs/ext2_err.et.in |   3 +
 lib/ext2fs/ext2fs.h       |   2 +
 lib/ext2fs/fileio.c       | 197 +++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 201 insertions(+), 1 deletion(-)

diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index d20c6b7..6e79b97 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -476,4 +476,7 @@ ec	EXT2_ET_MMP_CSUM_INVALID,
 ec	EXT2_ET_FILE_EXISTS,
 	"Ext2 file already exists"
 
+ec	EXT2_ET_SEEK_BEYOND_EOF,
+	"lseek beyond the EOF"
+
 	end
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 7139b4d..ce7c38a 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -160,6 +160,8 @@ typedef struct ext2_file *ext2_file_t;
 #define EXT2_SEEK_SET	0
 #define EXT2_SEEK_CUR	1
 #define EXT2_SEEK_END	2
+#define EXT2_SEEK_DATA	3
+#define EXT2_SEEK_HOLE	4
 
 /*
  * Flags for the ext2_filsys structure and for ext2fs_open()
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
index 1f7002c..6cb2e43 100644
--- a/lib/ext2fs/fileio.c
+++ b/lib/ext2fs/fileio.c
@@ -312,10 +312,201 @@ fail:
 	return retval;
 }
 
+static errcode_t ext2fs_file_llseek_data_ext(ext2_file_t file, __u64 offset)
+{
+	ext2_extent_handle_t	handle = 0;
+	struct ext2fs_extent	extent;
+	ext2_filsys	fs = file->fs;
+	errcode_t	retval = 0;
+	unsigned int	dataoff;
+
+	retval = ext2fs_extent_open2(fs, file->ino, &file->inode, &handle);
+	if (retval)
+		return retval;
+
+	while (file->blockno * fs->blocksize < EXT2_I_SIZE(&file->inode)) {
+		retval = ext2fs_extent_goto(handle, file->blockno);
+		if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND)
+			goto done;
+		if (retval == EXT2_ET_EXTENT_NOT_FOUND) {
+			file->blockno++;
+		} else {
+			retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
+						   &extent);
+			if (retval)
+				goto done;
+			/*
+			 * Here we skip uninit block because uninit block is
+			 * as a hole.
+			 */
+			if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
+				file->blockno++;
+				continue;
+			}
+			dataoff = file->blockno - extent.e_lblk;
+			if (file->blockno >= extent.e_lblk &&
+			    dataoff <= extent.e_len) {
+				if (file->blockno == offset / fs->blocksize)
+					file->pos = offset;
+				else
+					file->pos = file->blockno *
+						    fs->blocksize;
+				break;
+			}
+		}
+	}
+
+done:
+	ext2fs_extent_free(handle);
+	return retval;
+}
+
+static errcode_t ext2fs_file_llseek_data_ind(ext2_file_t file, __u64 offset)
+{
+	ext2_filsys	fs = file->fs;
+	errcode_t	retval = 0;
+
+	while (file->blockno * fs->blocksize < EXT2_I_SIZE(&file->inode)) {
+		retval = ext2fs_bmap2(fs, file->ino, &file->inode, BMAP_BUFFER,
+				      0, file->blockno, 0, &file->physblock);
+		if (retval)
+			return retval;
+		/*
+		 * Here we don't care about uninit block because indirect-based
+		 * file doesn't support it.
+		 */
+		if (file->physblock == 0) {
+			file->blockno++;
+		} else {
+			if (file->blockno == offset / fs->blocksize)
+				file->pos = offset;
+			else
+				file->pos = file->blockno * fs->blocksize;
+			break;
+		}
+	}
+
+	return retval;
+}
+
+static errcode_t ext2fs_file_llseek_data(ext2_file_t file, __u64 offset)
+{
+	ext2_filsys	fs = file->fs;
+	errcode_t	retval;
+
+	file->blockno = offset / fs->blocksize;
+
+	if (file->inode.i_flags & EXT4_EXTENTS_FL)
+		retval = ext2fs_file_llseek_data_ext(file, offset);
+	else
+		retval = ext2fs_file_llseek_data_ind(file, offset);
+
+	/* notify the caller that there is no any data */
+	if (file->blockno * fs->blocksize >= EXT2_I_SIZE(&file->inode))
+		return EXT2_ET_SEEK_BEYOND_EOF;
+
+	return retval;
+}
+
+static errcode_t ext2fs_file_llseek_hole_ext(ext2_file_t file, __u64 offset)
+{
+	ext2_extent_handle_t	handle = 0;
+	struct ext2fs_extent	extent;
+	ext2_filsys	fs = file->fs;
+	errcode_t	retval = 0;
+	unsigned int	dataoff;
+
+	retval = ext2fs_extent_open2(fs, file->ino, &file->inode, &handle);
+	if (retval)
+		return retval;
+
+	while (file->blockno * fs->blocksize < EXT2_I_SIZE(&file->inode)) {
+		retval = ext2fs_extent_goto(handle, file->blockno);
+		if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND)
+			goto done;
+		if (retval == EXT2_ET_EXTENT_NOT_FOUND) {
+			if (file->blockno == offset / fs->blocksize)
+				file->pos = offset;
+			else
+				file->pos = file->blockno * fs->blocksize;
+			break;
+		} else {
+			retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
+						   &extent);
+			if (retval)
+				goto done;
+			/* Here uninit block is as a hole */
+			if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
+				if (file->blockno == offset / fs->blocksize)
+					file->pos = offset;
+				else
+					file->pos = file->blockno *
+						    fs->blocksize;
+				break;
+			}
+			dataoff = file->blockno - extent.e_lblk;
+			if (file->blockno >= extent.e_lblk &&
+			    dataoff <= extent.e_len)
+				file->blockno = extent.e_lblk + extent.e_len;
+		}
+	}
+
+done:
+	ext2fs_extent_free(handle);
+	return retval;
+}
+
+static errcode_t ext2fs_file_llseek_hole_ind(ext2_file_t file, __u64 offset)
+{
+	ext2_filsys	fs = file->fs;
+	errcode_t	retval = 0;
+
+	while (file->blockno * fs->blocksize < EXT2_I_SIZE(&file->inode)) {
+		retval = ext2fs_bmap2(fs, file->ino, &file->inode, BMAP_BUFFER,
+				      0, file->blockno, 0, &file->physblock);
+		if (retval)
+			return retval;
+		/*
+		 * Here we don't care about uninit block because indirect-based
+		 * file doesn't support it.
+		 */
+		if (file->physblock == 0) {
+			if (file->blockno == offset / fs->blocksize)
+				file->pos = offset;
+			else
+				file->pos = file->blockno * fs->blocksize;
+			break;
+		} else {
+			file->blockno++;
+		}
+	}
+
+	return retval;
+}
+
+static errcode_t ext2fs_file_llseek_hole(ext2_file_t file, __u64 offset)
+{
+	ext2_filsys	fs = file->fs;
+	errcode_t	retval;
+
+	if (offset >= EXT2_I_SIZE(&file->inode))
+		return EXT2_ET_SEEK_BEYOND_EOF;
+
+	file->blockno = offset / fs->blocksize;
+
+	if (file->inode.i_flags & EXT4_EXTENTS_FL)
+		retval = ext2fs_file_llseek_hole_ext(file, offset);
+	else
+		retval = ext2fs_file_llseek_hole_ind(file, offset);
+
+	return retval;
+}
+
 errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
 			    int whence, __u64 *ret_pos)
 {
 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+	errcode_t retval = 0;
 
 	if (whence == EXT2_SEEK_SET)
 		file->pos = offset;
@@ -323,13 +514,17 @@ errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
 		file->pos += offset;
 	else if (whence == EXT2_SEEK_END)
 		file->pos = EXT2_I_SIZE(&file->inode) + offset;
+	else if (whence == EXT2_SEEK_DATA)
+		retval = ext2fs_file_llseek_data(file, offset);
+	else if (whence == EXT2_SEEK_HOLE)
+		retval = ext2fs_file_llseek_hole(file, offset);
 	else
 		return EXT2_ET_INVALID_ARGUMENT;
 
 	if (ret_pos)
 		*ret_pos = file->pos;
 
-	return 0;
+	return retval;
 }
 
 errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
-- 
1.7.12.rc2.18.g61b472e


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2 v4] debugfs: dump a sparse file
  2013-01-25  3:39 [PATCH 0/2 v4] dump a sparse file in debugfs Zheng Liu
  2013-01-25  3:39 ` [PATCH 1/2 v4] libext2fs: introduce lseek SEEK_DATA/HOLE Zheng Liu
@ 2013-01-25  3:39 ` Zheng Liu
  2013-05-13 13:33 ` [PATCH 0/2 v4] dump a sparse file in debugfs Zheng Liu
  2 siblings, 0 replies; 4+ messages in thread
From: Zheng Liu @ 2013-01-25  3:39 UTC (permalink / raw)
  To: linux-ext4; +Cc: Theodore Ts'o, Zheng Liu

From: Zheng Liu <wenqing.lz@taobao.com>

When ext2fs_file_open() is called with EXT2_FILE_SPAESE flag,
ext2fs_file_read() will return EXT2_ET_READ_HOLE_FOUND if it
meets a hole/uninitialized block.  Then we can handle a sparse
file in dump_file() according to this return value.

Cc: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
---
 debugfs/dump.c            | 48 +++++++++++++++++++++++++++++++++++++++--------
 lib/ext2fs/ext2_err.et.in |  3 +++
 lib/ext2fs/ext2fs.h       |  1 +
 lib/ext2fs/fileio.c       | 11 +++++++++--
 4 files changed, 53 insertions(+), 10 deletions(-)

diff --git a/debugfs/dump.c b/debugfs/dump.c
index 9409ab6..3f93fa9 100644
--- a/debugfs/dump.c
+++ b/debugfs/dump.c
@@ -107,13 +107,20 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
 	struct ext2_inode	inode;
 	char		*buf = 0;
 	ext2_file_t	e2_file;
-	int		nbytes;
+	ext2_off64_t	ret_pos, offset;
+	int		nbytes, flags = 0;
 	unsigned int	got, blocksize = current_fs->blocksize;
 
 	if (debugfs_read_inode(ino, &inode, cmdname))
 		return;
 
-	retval = ext2fs_file_open(current_fs, ino, 0, &e2_file);
+	/*
+	 * We need to handle stdout because this function is called by
+	 * do_cat() and do_dump().
+	 */
+	if (fd != 1)
+		flags = EXT2_FILE_SPARSE;
+	retval = ext2fs_file_open(current_fs, ino, flags, &e2_file);
 	if (retval) {
 		com_err(cmdname, retval, "while opening ext2 file");
 		return;
@@ -125,13 +132,38 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
 	}
 	while (1) {
 		retval = ext2fs_file_read(e2_file, buf, blocksize, &got);
-		if (retval)
+		if (retval && retval != EXT2_ET_READ_HOLE_FOUND)
 			com_err(cmdname, retval, "while reading ext2 file");
-		if (got == 0)
-			break;
-		nbytes = write(fd, buf, got);
-		if ((unsigned) nbytes != got)
-			com_err(cmdname, errno, "while writing file");
+		if (retval == EXT2_ET_READ_HOLE_FOUND) {
+			if (got) {
+				nbytes = write(fd, buf, got);
+				if ((unsigned) nbytes != got)
+					com_err(cmdname, errno,
+						"while writing file");
+			}
+			retval = ext2fs_file_llseek(e2_file, 0, EXT2_SEEK_CUR,
+						    &offset);
+			if (retval)
+				com_err(cmdname, retval,
+					"while lseeking ext2 file");
+			retval = ext2fs_file_llseek(e2_file, offset,
+						    EXT2_SEEK_DATA, &ret_pos);
+			if (retval == EXT2_ET_SEEK_BEYOND_EOF)
+				break;
+			if (retval)
+				com_err(cmdname, retval,
+					"while lseeking ext2 file");
+			ret_pos = ext2fs_llseek(fd, ret_pos, SEEK_SET);
+			if (ret_pos < 0)
+				com_err(cmdname, retval,
+					"while lseeking target file");
+		} else {
+			if (got == 0)
+				break;
+			nbytes = write(fd, buf, got);
+			if ((unsigned) nbytes != got)
+				com_err(cmdname, errno, "while writing file");
+		}
 	}
 	if (buf)
 		ext2fs_free_mem(&buf);
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 6e79b97..f854df0 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -479,4 +479,7 @@ ec	EXT2_ET_FILE_EXISTS,
 ec	EXT2_ET_SEEK_BEYOND_EOF,
 	"lseek beyond the EOF"
 
+ec	EXT2_ET_READ_HOLE_FOUND,
+	"We read a hole/uninitialized block with EXT2_FILE_SPARSE flag"
+
 	end
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index ce7c38a..e757b40 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -149,6 +149,7 @@ typedef struct ext2_struct_dblist *ext2_dblist;
 
 #define EXT2_FILE_WRITE		0x0001
 #define EXT2_FILE_CREATE	0x0002
+#define EXT2_FILE_SPARSE	0x0004
 
 #define EXT2_FILE_MASK		0x00FF
 
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
index 6cb2e43..be658d8 100644
--- a/lib/ext2fs/fileio.c
+++ b/lib/ext2fs/fileio.c
@@ -185,11 +185,12 @@ static errcode_t load_buffer(ext2_file_t file, int dontfill)
 {
 	ext2_filsys	fs = file->fs;
 	errcode_t	retval;
+	int		ret_flags = 0;
 
 	if (!(file->flags & EXT2_FILE_BUF_VALID)) {
 		retval = ext2fs_bmap2(fs, file->ino, &file->inode,
-				     BMAP_BUFFER, 0, file->blockno, 0,
-				     &file->physblock);
+				     BMAP_BUFFER, 0, file->blockno,
+				     &ret_flags, &file->physblock);
 		if (retval)
 			return retval;
 		if (!dontfill) {
@@ -203,6 +204,12 @@ static errcode_t load_buffer(ext2_file_t file, int dontfill)
 				memset(file->buf, 0, fs->blocksize);
 		}
 		file->flags |= EXT2_FILE_BUF_VALID;
+		if (file->flags & EXT2_FILE_SPARSE) {
+			if (file->physblock == 0 ||
+			    (ret_flags & BMAP_RET_UNINIT)) {
+				return EXT2_ET_READ_HOLE_FOUND;
+			}
+		}
 	}
 	return 0;
 }
-- 
1.7.12.rc2.18.g61b472e


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2 v4] dump a sparse file in debugfs
  2013-01-25  3:39 [PATCH 0/2 v4] dump a sparse file in debugfs Zheng Liu
  2013-01-25  3:39 ` [PATCH 1/2 v4] libext2fs: introduce lseek SEEK_DATA/HOLE Zheng Liu
  2013-01-25  3:39 ` [PATCH 2/2 v4] debugfs: dump a sparse file Zheng Liu
@ 2013-05-13 13:33 ` Zheng Liu
  2 siblings, 0 replies; 4+ messages in thread
From: Zheng Liu @ 2013-05-13 13:33 UTC (permalink / raw)
  To: linux-ext4; +Cc: Zheng Liu, Theodore Ts'o

On Fri, Jan 25, 2013 at 11:39:03AM +0800, Zheng Liu wrote:
> Hi all,
> 
> This is the fourth try to support to dump a sparse file in debugfs.  In this
> patch series the only change is using ext2fs_llseek() in dump_file to get a
> better portability.

Hi Ted,

Could please take a look at this patch series?  It has been sent out
for a long time.  I have forgotten it completely until I clean up my
e2fsprogs tree.  I try to rebase this patch series against the latest
master branch of e2fsprogs tree, and it can be applied without any
changes.

Thanks,
                                                - Zheng

> 
> v4 <- v3:
>  - call ext2fs_llseek() in dump_file to seek to the next data because of better
>    portability
> 
> v3 <- v2:
>  - use extent interfaces to handle extent-based file in seek_data/hole function
>  - call ext2fs_file_llseek() to retrieve current offset in dump_file()
> 
> v2 <- v1:
>  - split original patch into two parts.
>  - make code clearly according to Ted's suggestions
> 
> Regards,
> 						- Zheng
> 
> Zheng Liu (2):
>   libext2fs: introduce lseek SEEK_DATA/HOLE
>   debugfs: dump a sparse file
> 
>  debugfs/dump.c            |  48 +++++++++--
>  lib/ext2fs/ext2_err.et.in |   6 ++
>  lib/ext2fs/ext2fs.h       |   3 +
>  lib/ext2fs/fileio.c       | 208 +++++++++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 254 insertions(+), 11 deletions(-)
> 
> -- 
> 1.7.12.rc2.18.g61b472e
> 

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-05-13 13:16 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-25  3:39 [PATCH 0/2 v4] dump a sparse file in debugfs Zheng Liu
2013-01-25  3:39 ` [PATCH 1/2 v4] libext2fs: introduce lseek SEEK_DATA/HOLE Zheng Liu
2013-01-25  3:39 ` [PATCH 2/2 v4] debugfs: dump a sparse file Zheng Liu
2013-05-13 13:33 ` [PATCH 0/2 v4] dump a sparse file in debugfs Zheng Liu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).