[Ocfs2-tools-devel] [PATCH 1/1] Add truncate for "clear
sparse" function in tunefs,
Mark Fasheh
mark.fasheh at oracle.com
Tue Nov 13 11:26:11 PST 2007
This patch fails the following scenario:
$ ./reserve_space foo resv 0 0 $[10*1024*1024]File:
foo
cmd = foo
l_whence = 0
l_start = 0
l_len = 10485760
$ ./truncate foo 65536
Truncating foo to 65536
[reserve_space and truncate are taken from ocfs2-test]
$ debugfs.ocfs2 /dev/sde2
debugfs: stat foo
Inode: 72890 Mode: 0644 Generation: 4289956910 (0xffb38c2e)
FS Generation: 2776784650 (0xa5825f0a)
Type: Regular Attr: 0x0 Flags: Valid
User: 0 (root) Group: 0 (root) Size: 65536
Links: 1 Clusters: 2560
ctime: 0x4739f672 -- Wed Dec 31 16:00:00 1969
atime: 0x4739f671 -- Wed Dec 31 16:00:00 1969
mtime: 0x4739f672 -- Wed Dec 31 16:00:00 1969
dtime: 0x0 -- Wed Dec 31 16:00:00 1969
ctime_nsec: 0x3897a5e6 -- 949462502
atime_nsec: 0x010a910e -- 17469710
mtime_nsec: 0x3897a5e6 -- 949462502
Last Extblk: 0
Sub Alloc Slot: 0 Sub Alloc Bit: 185
Tree Depth: 0 Count: 243 Next Free Rec: 1
## Offset Clusters Block# Flags
0 0 2560 96769 0x0
$ tunefs.ocfs2 --fs-features=nounwritten /dev/sde2
tunefs.ocfs2 1.4.0
We have 9688495 clusters free and need 0 clusters for sparse files, 0
clusters for more extent blocks and will need to clear 0 clusters of
unwritten extents.
Modify feature "nounwritten" for the volume
Proceed (y/N): y
Wrote Superblock
$ debugfs.ocfs2 /dev/sde2debugfs.ocfs2 1.4.0
debugfs: stat foo
Inode: 72890 Mode: 0644 Generation: 4289956910 (0xffb38c2e)
FS Generation: 2776784650 (0xa5825f0a)
Type: Regular Attr: 0x0 Flags: Valid
User: 0 (root) Group: 0 (root) Size: 65536
Links: 1 Clusters: 2560
ctime: 0x4739f672 -- Wed Dec 31 16:00:00 1969
atime: 0x4739f671 -- Wed Dec 31 16:00:00 1969
mtime: 0x4739f672 -- Wed Dec 31 16:00:00 1969
dtime: 0x0 -- Wed Dec 31 16:00:00 1969
ctime_nsec: 0x3897a5e6 -- 949462502
atime_nsec: 0x010a910e -- 17469710
mtime_nsec: 0x3897a5e6 -- 949462502
Last Extblk: 0
Sub Alloc Slot: 0 Sub Alloc Bit: 185
Tree Depth: 0 Count: 243 Next Free Rec: 1
## Offset Clusters Block# Flags
0 0 2560 96769 0x0
So, the existing unwritten extents code zero's the entire extent because
it's straddling i_size. Otherwise, the file isn't getting truncate which is
not what I think you expected to happen.
I found the problem, it's noted below...
On Tue, Nov 13, 2007 at 04:41:26PM +0800, tao.ma wrote:
> take 2
>
> Modification from V1 to V2:
> Move truncate process to the end of operation.
> We may need to truncate an unwritten extent sometime. So if we truncate the file
> first, the unwritten extent information stored in clear_ctxt may be outdated.
> So move it to the end.
>
> Signed-off-by: Tao Ma <tao.ma at oracle.com>
> ---
> tunefs.ocfs2/sparse_file.c | 65 +++++++++++++++++++++++++++++++++++++++-----
> 1 files changed, 58 insertions(+), 7 deletions(-)
>
> diff --git a/tunefs.ocfs2/sparse_file.c b/tunefs.ocfs2/sparse_file.c
> index 8ef6710..06782f6 100644
> --- a/tunefs.ocfs2/sparse_file.c
> +++ b/tunefs.ocfs2/sparse_file.c
> @@ -67,10 +67,14 @@ struct unwritten_list {
> * unwritten_list. Since filling up a hole may need a new extent record and
> * lead to some new extent block, the total hole number in the sparse file
> * will also be recorded.
> + *
> + * Some sparse file may also have some clusters which exceed the limit of
> + * i_size, and they should be truncated.
> */
> struct sparse_file {
> uint64_t blkno;
> uint32_t holes_num;
> + int truncate;
> struct hole_list *holes;
> struct unwritten_list *unwritten;
> struct sparse_file *next;
> @@ -208,6 +212,7 @@ static void list_sparse_iterate(void *priv_data,
> * Iterate a file.
> * Call "func" when we meet with a hole.
> * Call "unwritten_func" when we meet with unwritten clusters.
> + * Call "seen_exceed" when we see some clusters exceed i_size.
> */
> static errcode_t iterate_file(ocfs2_filesys *fs,
> struct ocfs2_dinode *di,
> @@ -218,10 +223,12 @@ static errcode_t iterate_file(ocfs2_filesys *fs,
> uint32_t start,
> uint32_t len,
> uint64_t p_start),
> + void (*seen_exceed)(void *priv_data),
> void *priv_data)
> {
> errcode_t ret;
> uint32_t clusters, v_cluster = 0, p_cluster, num_clusters;
> + uint32_t get_clusters = 0;
> uint64_t p_blkno;
> uint16_t extent_flags;
> ocfs2_cached_inode *ci = NULL;
> @@ -250,7 +257,8 @@ static errcode_t iterate_file(ocfs2_filesys *fs,
>
> if (func)
> func(priv_data, v_cluster, num_clusters);
> - }
> + } else
> + get_clusters += num_clusters;
>
> if ((extent_flags & OCFS2_EXT_UNWRITTEN) && unwritten_func) {
> p_blkno = ocfs2_clusters_to_blocks(fs, p_cluster);
> @@ -261,6 +269,17 @@ static errcode_t iterate_file(ocfs2_filesys *fs,
> v_cluster += num_clusters;
> }
>
> + /*
> + * If there are some extra clusters we need to record them.
> + * There are 2 scenarios:
> + * 1. there are more cotinguous clusters allocated in which case
> + * get_clusters > di->i_clusters
> + * 2. there are more clusters allocated after i_size in which case
> + * get_clusters < di->i_clusters
> + */
> + if (get_clusters != di->i_clusters && seen_exceed)
> + seen_exceed(priv_data);
This needs to compare against 'clusters' (as computed above in that
function), not 'i_clusters'. i_clusters will always equal the total number
of clusters in the inode, irregardless of i_size, so you won't hit this in
the case that the last extent includes i_size, but goes too far.
--Mark
--
Mark Fasheh
Senior Software Developer, Oracle
mark.fasheh at oracle.com
More information about the Ocfs2-tools-devel
mailing list