Hi

I have a patchset here for a problem which makes using aufs very hard for me:


=== 01-bugfix-in-au_add_till_max.patch) ===

If argument b is set to 0, au_add_till_max returns the value of constant ULLONG_MAX. In this case, old is equal to a and the condition fails.


=== 02-new-function-au_add_muldiv_till_max.patch) ===

Preparation patch for 03-bugfix-sums-with-different-block-size.patch

A new function au_add_muldiv_till_max which works like au_add_till_max but adds the result of b*mul/div instead of just b.

NEED SOME HELP HERE: the function is not overflow-safe yet. I think there must be such functions in the kernel already, but I'm to new to know where to find it.

Possibly this function could also be implemented by using bit shifting.


=== 03-bugfix-sums-with-different-block-size.patch ===

If aufs is mounted in sum mode, but the source file systems have different block sizes, the result of the statfs is the sum of all block counts which does not make sense. This patch corrects this problem by normalizing the block counts to the same block size and then adds them.

In my case, I have a squashfs system as root with data but no free space (read only file system) and a tmpfs. Both have very different block sizes. This could even result in a f_bfree bigger than f_blocks.



=============

PLEASE REVIEW MY PATCH CAREFULLY.

It is my first kernel-code work. I think the changes in au_statfs_sum
are quite good, but au_add_muldiv_till_max is just a hack. I did not
know how to handle an overflow in the multiplication, and there an
overflow is much more likely than in the addition. Maybe bit-shifting is
the way-to-go, but then you need to count bits in bsize (mul and div),
which is much more complicated, and you have to be ready to shift in
both ways.

Patches are against origin/aufs3.0 in aufs3-standalone, but I also
tested it with the aufs2.2-38 branch in aufs2-standalone.

=============


Example:
/dev/loop0 17152 17152 0 100% /root/aufstest/_L1_root (squashfs; block size 131072)
tmp 253488 16 253472 1% /root/aufstest/_L2_tmp (tmpfs, block size 4096)

mount -t aufs -o dirs=/root/aufstest/_L2_tmp=rw:/root/aufstest/_L1_root=ro,sum none _aufs

Result (without patch, something like):
none - - - ?% /root/aufstest/_aufs

Result (with patch):
none 270640 17168 253472 7% /root/aufstest/_aufs

output of "strace df -h _L1_root/ _L2_tmp/ _aufs 2>&1 | grep statfs":

before:
statfs64("_L1_root/", 84, {f_type=0x73717368, f_bsize=131072, f_blocks=134, f_bfree=0, f_bavail=0, f_files=13, f_ffree=0, f_fsid={1792, 0}, f_namelen=256, f_frsize=131072}) = 0 statfs64("_L2_tmp/", 84, {f_type=0x1021994, f_bsize=4096, f_blocks=63372, f_bfree=63368, f_bavail=63368, f_files=63372, f_ffree=63364, f_fsid={0, 0}, f_namelen=255, f_frsize=4096}) = 0 statfs64("_aufs", 84, {f_type=0x61756673, f_bsize=4096, f_blocks=63506, f_bfree=18446744073709551615, f_bavail=18446744073709551615, f_files=63385, f_ffree=18446744073709551615, f_fsid={0, 0}, f_namelen=242, f_frsize=4096}) = 0

after:
statfs64("_L1_root/", 84, {f_type=0x73717368, f_bsize=131072, f_blocks=134, f_bfree=0, f_bavail=0, f_files=13, f_ffree=0, f_fsid={1792, 0}, f_namelen=256, f_frsize=131072}) = 0 statfs64("_L2_tmp/", 84, {f_type=0x1021994, f_bsize=4096, f_blocks=63372, f_bfree=63368, f_bavail=63368, f_files=63372, f_ffree=63364, f_fsid={0, 0}, f_namelen=255, f_frsize=4096}) = 0 statfs64("_aufs", 84, {f_type=0x61756673, f_bsize=4096, f_blocks=67660, f_bfree=63368, f_bavail=63368, f_files=63385, f_ffree=63364, f_fsid={0, 0}, f_namelen=242, f_frsize=4096}) = 0


My testcase (Makefile, to use in a new empty directory):
--------
all: 5stattest.stamp

fullclean: clean
        $(RM) 1data/
        $(RM) 2data.squashfs *.stamp

clean:
        $(RM) 3mount.stamp 4dftest.stamp 5stattest.stamp
        -umount ./_aufs
        -umount ./_L1_root
        -umount ./_L2_tmp
        -rmdir _L1_root _L2_tmp _aufs
        test ! -d _L1_root
        test ! -d _L2_tmp
        test ! -d _aufs
        @echo "successful."

1data.stamp:
        mkdir 1data/
        dd if=/dev/urandom of=1data/a bs=512 count=1334
        dd if=/dev/urandom of=1data/b bs=512 count=112
        dd if=/dev/urandom of=1data/c bs=512 count=11322
        dd if=/dev/urandom of=1data/d bs=512 count=4322
        touch 1data.stamp

2data.squashfs: 1data.stamp
        mksquashfs 1data/ 2data.squashfs

3mount.stamp: 2data.squashfs
        mkdir _L1_root
        mount -oloop 2data.squashfs _L1_root
        mkdir _L2_tmp
        mount -t tmpfs tmp _L2_tmp
        mkdir _aufs
        mount -t aufs -o dirs=$(PWD)/_L2_tmp=rw:$(PWD)/_L1_root=ro,sum none 
_aufs
        touch 3mount.stamp

4dftest.stamp: 3mount.stamp
        df -h _aufs
        echo test >_aufs/abc
        df -h _aufs
        touch 4dftest.stamp

5stattest.stamp: 4dftest.stamp
        stat -c"%-14n %o %b %B" _L1_root _L2_tmp _aufs
        strace df -h _L1_root/ _L2_tmp/ _aufs 2>&1 | grep statfs
        touch 5stattest.stamp
-------


Bugfix: au_add_till_max wrongly detects overflow if b==0

If argument b is set to 0, au_add_till_max returns the value of constant ULLONG_MAX. In this case, old is equal to a and the condition fails.
Index: aufs3-standalone.git/fs/aufs/super.c
===================================================================
--- aufs3-standalone.git.orig/fs/aufs/super.c	2012-03-13 01:44:21.000000000 +0100
+++ aufs3-standalone.git/fs/aufs/super.c	2012-03-13 01:50:55.000000000 +0100
@@ -305,7 +305,7 @@
 
 	old = a;
 	a += b;
-	if (old < a)
+	if (old <= a)
		return a;
	return ULLONG_MAX;

New function: au_add_muldiv_till_max

Preparation patch for bugfix-sums-with-different-block-size.patch

A new function au_add_muldiv_till_max which works like au_add_till_max but adds the result of b*mul/div instead of just b.

NEED SOME HELP HERE: the function is not overflow-safe yet. I think there must be such functions in the kernel already, but I'm to new to know where to find it.

Possibly this function could also be implemented by using bit shifting.
===================================================================
--- aufs3-standalone.git.orig/fs/aufs/super.c	2012-03-13 21:47:55.000000000 +0100
+++ aufs3-standalone.git/fs/aufs/super.c	2012-03-13 22:28:48.000000000 +0100
@@ -310,6 +310,19 @@
 	return ULLONG_MAX;
 }
 
+static u64 au_add_muldiv_till_max(u64 a, u64 b, u64 mul, u64 div)
+{
+	u64 old;
+
+	b *= mul;
+
+	old = a;
+	a += div64_u64(b, div);
+	if (old <= a)
+		return a;
+	return ULLONG_MAX;
+}
+
 static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf)
 {
 	int err;
Bugfix: au_statfs_sum calculates wrong sums when different block sizes are used

If aufs is mounted in sum mode, but the source file systems have different block sizes, the result of the statfs is the sum of all block counts which does not make sense. This patch corrects this problem by normalizing the block counts to the same block size and then adds them.
Index: aufs3-standalone.git/fs/aufs/super.c
===================================================================
--- aufs3-standalone.git.orig/fs/aufs/super.c	2012-03-13 01:52:16.000000000 +0100
+++ aufs3-standalone.git/fs/aufs/super.c	2012-03-13 01:53:06.000000000 +0100
@@ -326,7 +326,7 @@
 static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf)
 {
 	int err;
-	u64 blocks, bfree, bavail, files, ffree;
+	u64 blocks, bfree, bavail, files, ffree, bsize;
 	aufs_bindex_t bend, bindex, i;
 	unsigned char shared;
 	struct path h_path;
@@ -338,6 +338,14 @@
 	files = 0;
 	ffree = 0;
 
+	// we need an initial bsize to calculate correct f_blocks
+	h_path.mnt = au_sbr_mnt(sb, 0);
+	h_path.dentry = h_path.mnt->mnt_root;
+	err = vfs_statfs(&h_path, buf);
+	if (unlikely(err))
+		goto out;
+	bsize = buf->f_bsize;
+
 	err = 0;
 	bend = au_sbend(sb);
 	for (bindex = bend; bindex >= 0; bindex--) {
@@ -355,9 +363,9 @@
 		if (unlikely(err))
 			goto out;
 
-		blocks = au_add_till_max(blocks, buf->f_blocks);
-		bfree = au_add_till_max(bfree, buf->f_bfree);
-		bavail = au_add_till_max(bavail, buf->f_bavail);
+		blocks = au_add_muldiv_till_max(blocks, buf->f_blocks, buf->f_bsize, bsize );
+		bfree  = au_add_muldiv_till_max(bfree,  buf->f_bfree,  buf->f_bsize, bsize );
+		bavail = au_add_muldiv_till_max(bavail, buf->f_bavail, buf->f_bsize, bsize );
 		files = au_add_till_max(files, buf->f_files);
 		ffree = au_add_till_max(ffree, buf->f_ffree);
 	}
------------------------------------------------------------------------------
Keep Your Developer Skills Current with LearnDevNow!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-d2d

Reply via email to