Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 453

kernel-2.6.18-238.el5.src.rpm

From: Jeff Layton <jlayton@redhat.com>
Date: Fri, 30 Oct 2009 08:14:30 -0400
Subject: [cifs] libfs: sb->s_maxbytes casts to a signed value
Message-id: 1256904870-1610-1-git-send-email-jlayton@redhat.com
O-Subject: [RHEL5 PATCH] BZ#486092: cifs/libfs: fix sb->s_maxbytes so that it casts properly to a signed value
Bugzilla: 486092
RH-Acked-by: Peter Staubach <staubach@redhat.com>

This off-by-one bug causes sendfile() to not work properly. When a task
calls sendfile() on a file on a CIFS filesystem, the syscall returns -1
and sets errno to EOVERFLOW. The sendfile call itself though actually
seems to succeed.

do_sendfile() uses s_maxbytes to verify the returned offset of the file.
The problem there is that this value is cast to a signed value (loff_t).
When this is done on the s_maxbytes value that cifs uses, it becomes
negative and the comparisons against it fail. The first part of this
patch fixes the s_maxbytes values in CIFS to use the standard #define'd
values for this.

When do_sendfile() does this check, it actually checks against the
minimum s_maxbytes value of the two filesystems between which it is
splicing. The outfd for any sendfile call must be a socket, so this
problem also exists in get_sb_pseudo. By fixing this there, this may
also fix sendfile() on other 3rd party filesystems that set s_maxbytes
too large.

As part of this fix, I also pushed a patch upstream to make s_maxbytes
type an loff_t, but that change probably isn't suitable for RHEL.

This fixes the reproducer program I have that does a sendfile and also
fixes the situation where apache is serving from a CIFS share.

Signed-off-by: Jeff Layton <jlayton@redhat.com>

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index b7d5897..92cb173 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2482,10 +2482,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 		tcon->nocase = volume_info->nocase;
 	}
 	if (pSesInfo) {
-		if (pSesInfo->capabilities & CAP_LARGE_FILES) {
-			sb->s_maxbytes = (u64) 1 << 63;
-		} else
-			sb->s_maxbytes = (u64) 1 << 31;	/* 2 GB */
+		if (pSesInfo->capabilities & CAP_LARGE_FILES)
+			sb->s_maxbytes = MAX_LFS_FILESIZE;
+		else
+			sb->s_maxbytes = MAX_NON_LFS;
 	}
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10)
diff --git a/fs/libfs.c b/fs/libfs.c
index 7c12fa4..e09ecbf 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -208,7 +208,7 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name,
 		return PTR_ERR(s);
 
 	s->s_flags = MS_NOUSER;
-	s->s_maxbytes = ~0ULL;
+	s->s_maxbytes = MAX_LFS_FILESIZE;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = magic;