
From: Olaf Kirch <okir@suse.de>

A while ago, we fixed a problem in statfs on 64bit system that caused it
to return EOVERFLOW when the number of files reported by the underlying
file system was -1 (which happens for NFS for instance). The problematic
code was this:

        if (sizeof ubuf->f_blocks == 4) {
                if ((kbuf->f_blocks | kbuf->f_bfree |
                     kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
                    0xffffffff00000000ULL)
                        return -EOVERFLOW;
		...
	}

The problem was fixed by explicitly allowing f_files and f_ffree to be -1.

The same problem exists in fs/compat.c, and the attached patch fixes it
in a similar manner.

Signed-Off-By: Olaf Kirch <okir@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/compat.c |   22 ++++++++++++++++++----
 1 files changed, 18 insertions(+), 4 deletions(-)

diff -puN fs/compat.c~statfs-compat-functions-can-return-eoverflow-on-nfs fs/compat.c
--- 25/fs/compat.c~statfs-compat-functions-can-return-eoverflow-on-nfs	Wed Nov 10 13:37:28 2004
+++ 25-akpm/fs/compat.c	Wed Nov 10 13:37:28 2004
@@ -117,10 +117,17 @@ static int put_compat_statfs(struct comp
 {
 	
 	if (sizeof ubuf->f_blocks == 4) {
-		if ((kbuf->f_blocks | kbuf->f_bfree |
-		     kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
+		if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) &
 		    0xffffffff00000000ULL)
 			return -EOVERFLOW;
+		/* f_files and f_ffree may be -1; it's okay
+		 * to stuff that into 32 bits */
+		if (kbuf->f_files != 0xffffffffffffffffULL
+		 && (kbuf->f_files & 0xffffffff00000000ULL))
+			return -EOVERFLOW;
+		if (kbuf->f_ffree != 0xffffffffffffffffULL
+		 && (kbuf->f_ffree & 0xffffffff00000000ULL))
+			return -EOVERFLOW;
 	}
 	if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 	    __put_user(kbuf->f_type, &ubuf->f_type) ||
@@ -184,10 +191,17 @@ out:
 static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
 {
 	if (sizeof ubuf->f_blocks == 4) {
-		if ((kbuf->f_blocks | kbuf->f_bfree |
-		     kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
+		if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) &
 		    0xffffffff00000000ULL)
 			return -EOVERFLOW;
+		/* f_files and f_ffree may be -1; it's okay
+		 * to stuff that into 32 bits */
+		if (kbuf->f_files != 0xffffffffffffffffULL
+		 && (kbuf->f_files & 0xffffffff00000000ULL))
+			return -EOVERFLOW;
+		if (kbuf->f_ffree != 0xffffffffffffffffULL
+		 && (kbuf->f_ffree & 0xffffffff00000000ULL))
+			return -EOVERFLOW;
 	}
 	if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 	    __put_user(kbuf->f_type, &ubuf->f_type) ||
_
