linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Darrick J. Wong" <darrick.wong@oracle.com>
To: tytso@mit.edu, darrick.wong@oracle.com
Cc: linux-ext4@vger.kernel.org
Subject: [PATCH 25/31] libext2fs: find/alloc a range of empty blocks
Date: Sat, 20 Dec 2014 13:19:36 -0800	[thread overview]
Message-ID: <20141220211936.25563.24584.stgit@birch.djwong.org> (raw)
In-Reply-To: <20141220211640.25563.80596.stgit@birch.djwong.org>

Provide a function that, given a goal pblk and a range, will try to
find a run of free blocks to satisfy the allocation.  By default the
function will look anywhere in the filesystem for the run, though this
can be constrained with optional flags.  One flag indicates that the
range must start at the goal block; the other flag indicates that we
should not return a range shorter than len.

v2: Add a second function to allocate a range of blocks.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 lib/ext2fs/alloc.c  |  141 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ext2fs/ext2fs.h |   11 ++++
 2 files changed, 152 insertions(+)


diff --git a/lib/ext2fs/alloc.c b/lib/ext2fs/alloc.c
index 9901ca5..4c3b620 100644
--- a/lib/ext2fs/alloc.c
+++ b/lib/ext2fs/alloc.c
@@ -26,6 +26,16 @@
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+#undef DEBUG
+
+#ifdef DEBUG
+# define dbg_printf(f, a...)  do {printf(f, ## a); fflush(stdout); } while (0)
+#else
+# define dbg_printf(f, a...)
+#endif
+
 /*
  * Clear the uninit block bitmap flag if necessary
  */
@@ -346,3 +356,134 @@ no_blocks:
 		group = group & ~((1 << (log_flex)) - 1);
 	return ext2fs_group_first_block2(fs, group);
 }
+
+/*
+ * Starting at _goal_, scan around the filesystem to find a run of free blocks
+ * that's at least _len_ blocks long.  Possible flags:
+ * - EXT2_NEWRANGE_EXACT_GOAL: The range of blocks must start at _goal_.
+ * - EXT2_NEWRANGE_MIN_LENGTH: do not return a allocation shorter than _len_.
+ * - EXT2_NEWRANGE_ZERO_BLOCKS: Zero blocks pblk to pblk+plen before returning.
+ *
+ * The starting block is returned in _pblk_ and the length is returned via
+ * _plen_.  The blocks are not marked in the bitmap; the caller must mark
+ * however much of the returned run they actually use, hopefully via
+ * ext2fs_block_alloc_stats_range().
+ *
+ * This function can return a range that is longer than what was requested.
+ */
+errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal,
+			   blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk,
+			   blk64_t *plen)
+{
+	errcode_t retval;
+	blk64_t start, end, b;
+	int looped = 0;
+	blk64_t max_blocks = ext2fs_blocks_count(fs->super);
+
+	dbg_printf("%s: flags=0x%x goal=%llu len=%llu\n", __func__, flags,
+		   goal, len);
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+	if (len == 0 || (flags & ~EXT2_NEWRANGE_ALL_FLAGS))
+		return EXT2_ET_INVALID_ARGUMENT;
+	if (!map)
+		map = fs->block_map;
+	if (!map)
+		return EXT2_ET_NO_BLOCK_BITMAP;
+	if (!goal || goal >= ext2fs_blocks_count(fs->super))
+		goal = fs->super->s_first_data_block;
+
+	start = goal;
+	while (!looped || start <= goal) {
+		retval = ext2fs_find_first_zero_block_bitmap2(map, start,
+							      max_blocks - 1,
+							      &start);
+		if (retval == ENOENT) {
+			/*
+			 * If there are no free blocks beyond the starting
+			 * point, try scanning the whole filesystem, unless the
+			 * user told us only to allocate from _goal_, or if
+			 * we're already scanning the whole filesystem.
+			 */
+			if (flags & EXT2_NEWRANGE_FIXED_GOAL ||
+			    start == fs->super->s_first_data_block)
+				goto fail;
+			start = fs->super->s_first_data_block;
+			continue;
+		} else if (retval)
+			goto errout;
+
+		if (flags & EXT2_NEWRANGE_FIXED_GOAL && start != goal)
+			goto fail;
+
+		b = min(start + len - 1, max_blocks - 1);
+		retval =  ext2fs_find_first_set_block_bitmap2(map, start, b,
+							      &end);
+		if (retval == ENOENT)
+			end = b + 1;
+		else if (retval)
+			goto errout;
+
+		if (!(flags & EXT2_NEWRANGE_MIN_LENGTH) ||
+		    (end - start) >= len) {
+			/* Success! */
+			*pblk = start;
+			*plen = end - start;
+			dbg_printf("%s: new_range goal=%llu--%llu "
+				   "blk=%llu--%llu %llu\n",
+				   __func__, goal, goal + len - 1,
+				   *pblk, *pblk + *plen - 1, *plen);
+
+			for (b = start; b < end;
+			     b += fs->super->s_blocks_per_group)
+				clear_block_uninit(fs,
+						ext2fs_group_of_blk2(fs, b));
+			return 0;
+		}
+
+		if (flags & EXT2_NEWRANGE_FIXED_GOAL)
+			goto fail;
+		start = end;
+		if (start >= max_blocks) {
+			if (looped)
+				goto fail;
+			looped = 1;
+			start = fs->super->s_first_data_block;
+		}
+	}
+
+fail:
+	retval = EXT2_ET_BLOCK_ALLOC_FAIL;
+errout:
+	return retval;
+}
+
+errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal,
+			     blk_t len, blk64_t *ret)
+{
+	int newr_flags = EXT2_NEWRANGE_MIN_LENGTH;
+	errcode_t retval;
+	blk64_t plen;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+	if (len == 0 || (flags & ~EXT2_ALLOCRANGE_ALL_FLAGS))
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	if (flags & EXT2_ALLOCRANGE_FIXED_GOAL)
+		newr_flags |= EXT2_NEWRANGE_FIXED_GOAL;
+
+	retval = ext2fs_new_range(fs, newr_flags, goal, len, NULL, ret, &plen);
+	if (retval)
+		return retval;
+
+	if (plen < len)
+		return EXT2_ET_BLOCK_ALLOC_FAIL;
+
+	if (flags & EXT2_ALLOCRANGE_ZERO_BLOCKS) {
+		retval = ext2fs_zero_blocks2(fs, *ret, len, NULL, NULL);
+		if (retval)
+			return retval;
+	}
+
+	ext2fs_block_alloc_stats_range(fs, *ret, len, +1);
+	return retval;
+}
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index e117441..bfe0ecf 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -693,6 +693,17 @@ extern void ext2fs_set_alloc_block_callback(ext2_filsys fs,
 							      blk64_t *ret));
 blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino,
 			       struct ext2_inode *inode, blk64_t lblk);
+#define EXT2_NEWRANGE_FIXED_GOAL	(0x1)
+#define EXT2_NEWRANGE_MIN_LENGTH	(0x2)
+#define EXT2_NEWRANGE_ALL_FLAGS		(0x3)
+errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal,
+			   blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk,
+			   blk64_t *plen);
+#define EXT2_ALLOCRANGE_FIXED_GOAL	(0x1)
+#define EXT2_ALLOCRANGE_ZERO_BLOCKS	(0x2)
+#define EXT2_ALLOCRANGE_ALL_FLAGS	(0x3)
+errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal,
+			     blk_t len, blk64_t *ret);
 
 /* alloc_sb.c */
 extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs,


  parent reply	other threads:[~2014-12-20 21:19 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-20 21:16 [PATCH 00/31] e2fsprogs December 2014 patchbomb Darrick J. Wong
2014-12-20 21:16 ` [PATCH 01/31] misc: fix clang warnings and a resource leak Darrick J. Wong
2015-01-19 21:39   ` Theodore Ts'o
2014-12-20 21:16 ` [PATCH 02/31] debugfs: document new commands Darrick J. Wong
2014-12-20 21:17 ` [PATCH 03/31] libext2fs: zero blocks via FALLOC_FL_ZERO_RANGE in ext2fs_zero_blocks Darrick J. Wong
2014-12-20 21:17 ` [PATCH 04/31] libext2fs: ext2fs_new_block2() should call alloc_block hook Darrick J. Wong
2014-12-20 21:17 ` [PATCH 05/31] tune2fs: disable csum verification before resizing inode Darrick J. Wong
2014-12-20 21:17 ` [PATCH 06/31] e2fsck: clear i_block[] when there are too many bad mappings on a special inode Darrick J. Wong
2014-12-20 21:17 ` [PATCH 07/31] libext2fs/e2fsck: provide routines to read-ahead metadata Darrick J. Wong
2014-12-20 21:17 ` [PATCH 08/31] e2fsck: read-ahead metadata during passes 1, 2, and 4 Darrick J. Wong
2014-12-20 21:17 ` [PATCH 09/31] e2fsck: track directories to be rehashed with a bitmap Darrick J. Wong
2014-12-20 21:17 ` [PATCH 10/31] e2fsck: rebuild sparse extent trees/convert non-extent ext3 files Darrick J. Wong
2014-12-20 21:17 ` [PATCH 11/31] tests: verify proper rebuilding of sparse extent trees and block map file conversion Darrick J. Wong
2014-12-20 21:18 ` [PATCH 12/31] undo-io: add new calls to and speed up the undo io manager Darrick J. Wong
2014-12-20 21:18 ` [PATCH 13/31] undo-io: be more flexible about setting block size Darrick J. Wong
2014-12-20 21:18 ` [PATCH 14/31] undo-io: use a bitmap to track what we've already written Darrick J. Wong
2014-12-20 21:18 ` [PATCH 15/31] e2undo: fix memory leaks and tweak the error messages somewhat Darrick J. Wong
2014-12-20 21:18 ` [PATCH 16/31] e2undo: ditch tdb file, write everything to a flat file Darrick J. Wong
2015-01-08  1:36   ` Darrick J. Wong
2014-12-20 21:18 ` [PATCH 17/31] e2fsck: optionally create an undo file Darrick J. Wong
2014-12-20 21:18 ` [PATCH 18/31] resize2fs: optionally create " Darrick J. Wong
2014-12-20 21:18 ` [PATCH 19/31] tune2fs: " Darrick J. Wong
2014-12-20 21:19 ` [PATCH 20/31] mke2fs: " Darrick J. Wong
2014-12-20 21:19 ` [PATCH 21/31] debugfs: " Darrick J. Wong
2014-12-20 21:19 ` [PATCH 22/31] tests: test undo file creation in e2fsck/resize2fs/tune2fs/mke2fs Darrick J. Wong
2014-12-20 21:19 ` [PATCH 23/31] tests: test various features of the new e2undo format Darrick J. Wong
2014-12-20 21:19 ` [PATCH 24/31] libext2fs: support allocating uninit blocks in bmap2() Darrick J. Wong
2014-12-20 21:19 ` Darrick J. Wong [this message]
2014-12-20 21:19 ` [PATCH 26/31] libext2fs: add new hooks to support large allocations Darrick J. Wong
2014-12-20 21:19 ` [PATCH 27/31] libext2fs: implement fallocate Darrick J. Wong
2014-12-20 21:19 ` [PATCH 28/31] libext2fs: use fallocate for creating journals and hugefiles Darrick J. Wong
2014-12-20 21:20 ` [PATCH 29/31] debugfs: implement fallocate Darrick J. Wong
2014-12-20 21:20 ` [PATCH 30/31] tests: test debugfs punch command Darrick J. Wong
2014-12-22 18:53 ` [PATCH 32/31] libext2fs: initialize i_extra_isize when writing EAs Darrick J. Wong
2014-12-22 22:22   ` Andreas Dilger
2014-12-22 22:32     ` Darrick J. Wong
2014-12-22 22:55   ` [PATCH v2 " Darrick J. Wong
2014-12-22 18:55 ` [PATCH 33/31] e2fsck: on read error, don't rewrite blocks past the end of the fs Darrick J. Wong
2014-12-22 18:55 ` [PATCH 34/31] e2fsck: fix the journal recreation message Darrick J. Wong
2014-12-22 18:57 ` [PATCH 35/31] libext2fs: avoid pointless EA block allocation Darrick J. Wong
2014-12-22 18:57 ` [PATCH 36/31] libext2fs: strengthen i_extra_isize checks when reading/writing xattrs Darrick J. Wong
2014-12-22 18:57 ` [PATCH 37/31] libext2fs: fix tdb.c mmap leak Darrick J. Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20141220211936.25563.24584.stgit@birch.djwong.org \
    --to=darrick.wong@oracle.com \
    --cc=linux-ext4@vger.kernel.org \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).