* [PATCH 0/4] vfs: change sb->s_maxbytes to loff_t
@ 2009-08-07 18:57 Jeff Layton
2009-08-07 18:57 ` [PATCH 1/4] vfs: make get_sb_pseudo set s_maxbytes to value that can be cast to signed Jeff Layton
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Jeff Layton @ 2009-08-07 18:57 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: akpm, hch, rlove, msb, viro, hannes
Recently, I spent a day or so tracking down a long-standing problem with
CIFS and sendfile(). The problem turned out to be that CIFS was setting
s_maxbytes to a value that, when cast to a signed value, became
negative. This broke the offset checks in do_sendfile().
While I fixed this in CIFS, it turns out that this problem is actually a
little more widespread. Since setting s_maxbytes to a value larger than
MAX_LFS_FILESIZE breaks things, I believe it makes sense to turn
s_maxbytes into an loff_t. Most of the places that compare values to
s_maxbytes are comparing it against signed loff_t values, so this change
should help reduce the amount of implicit casting that's done in the
code.
I've looked at most of the places that use s_maxbytes and have tried to
fix areas that look like they might have problems with this change. It's
quite possible though that I've missed some, so a careful eye for that
when reviewing this would be a good thing.
This set is only lightly tested, but it's fairly straightforward.
Jeff Layton (4):
vfs: make get_sb_pseudo set s_maxbytes to value that can be cast to
signed
vfs: explicitly cast s_maxbytes in fiemap_check_ranges
vfs: change sb->s_maxbytes to a loff_t
vfs: remove redundant checks in do_sendfile
fs/ioctl.c | 9 +++++----
fs/libfs.c | 2 +-
fs/read_write.c | 11 -----------
fs/super.c | 10 ++++++++++
include/linux/fs.h | 2 +-
5 files changed, 17 insertions(+), 17 deletions(-)
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/4] vfs: make get_sb_pseudo set s_maxbytes to value that can be cast to signed
2009-08-07 18:57 [PATCH 0/4] vfs: change sb->s_maxbytes to loff_t Jeff Layton
@ 2009-08-07 18:57 ` Jeff Layton
2009-08-07 22:28 ` Johannes Weiner
2009-08-07 18:57 ` [PATCH 2/4] vfs: explicitly cast s_maxbytes in fiemap_check_ranges Jeff Layton
` (2 subsequent siblings)
3 siblings, 1 reply; 13+ messages in thread
From: Jeff Layton @ 2009-08-07 18:57 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: akpm, hch, rlove, msb, viro, hannes
This patch is a counterpart to the CIFS patch posted yesterday. I
believe either patch will fix the problem seen in do_sendfile since the
smaller s_maxbytes value for the two superblocks is used there.
get_sb_pseudo sets s_maxbytes to ~0ULL, which becomes negative when cast
to a signed value. Fix it to use MAX_LFS_FILESIZE which casts properly
to a positive signed value.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/libfs.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index ddfa899..dcec3d3 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -217,7 +217,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 = PAGE_SIZE;
s->s_blocksize_bits = PAGE_SHIFT;
s->s_magic = magic;
--
1.6.0.6
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/4] vfs: explicitly cast s_maxbytes in fiemap_check_ranges
2009-08-07 18:57 [PATCH 0/4] vfs: change sb->s_maxbytes to loff_t Jeff Layton
2009-08-07 18:57 ` [PATCH 1/4] vfs: make get_sb_pseudo set s_maxbytes to value that can be cast to signed Jeff Layton
@ 2009-08-07 18:57 ` Jeff Layton
2009-08-07 22:12 ` Johannes Weiner
2009-08-07 18:57 ` [PATCH 3/4] vfs: change sb->s_maxbytes to a loff_t Jeff Layton
2009-08-07 18:57 ` [PATCH 4/4] vfs: remove redundant checks in do_sendfile Jeff Layton
3 siblings, 1 reply; 13+ messages in thread
From: Jeff Layton @ 2009-08-07 18:57 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: akpm, hch, rlove, msb, viro, hannes
If fiemap_check_ranges is passed a large enough value, then it's
possible that the value would be cast to a signed value for comparison
against s_maxbytes when we change it to loff_t. Make sure that doesn't
happen by explicitly casting s_maxbytes to an unsigned value for the
purposes of comparison.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/ioctl.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 5612880..7b17a14 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -162,20 +162,21 @@ EXPORT_SYMBOL(fiemap_check_flags);
static int fiemap_check_ranges(struct super_block *sb,
u64 start, u64 len, u64 *new_len)
{
+ u64 maxbytes = (u64) sb->s_maxbytes;
+
*new_len = len;
if (len == 0)
return -EINVAL;
- if (start > sb->s_maxbytes)
+ if (start > maxbytes)
return -EFBIG;
/*
* Shrink request scope to what the fs can actually handle.
*/
- if ((len > sb->s_maxbytes) ||
- (sb->s_maxbytes - len) < start)
- *new_len = sb->s_maxbytes - start;
+ if (len > maxbytes || (maxbytes - len) < start)
+ *new_len = maxbytes - start;
return 0;
}
--
1.6.0.6
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/4] vfs: change sb->s_maxbytes to a loff_t
2009-08-07 18:57 [PATCH 0/4] vfs: change sb->s_maxbytes to loff_t Jeff Layton
2009-08-07 18:57 ` [PATCH 1/4] vfs: make get_sb_pseudo set s_maxbytes to value that can be cast to signed Jeff Layton
2009-08-07 18:57 ` [PATCH 2/4] vfs: explicitly cast s_maxbytes in fiemap_check_ranges Jeff Layton
@ 2009-08-07 18:57 ` Jeff Layton
2009-08-07 20:14 ` Andreas Dilger
2009-08-07 22:51 ` Johannes Weiner
2009-08-07 18:57 ` [PATCH 4/4] vfs: remove redundant checks in do_sendfile Jeff Layton
3 siblings, 2 replies; 13+ messages in thread
From: Jeff Layton @ 2009-08-07 18:57 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: akpm, hch, rlove, msb, viro, hannes
sb->s_maxbytes is supposed to indicate the maximum size of a file that
can exist on the filesystem. It's declared as an unsigned long long.
Even if a filesystem has no inherent limit that prevents it from using
every bit in that unsigned long long, it's still problematic to set it
to anything larger than MAX_LFS_FILESIZE. A lot of places implicitly
cast s_maxbytes to a signed value when doing comparisons against it
(usually using loff_t on the other side of the comparison). If it's
set too large then this cast makes it a negative number and generally
breaks the comparison.
Change s_maxbytes to be loff_t instead. That should help eliminate the
temptation to set it too large by making it a signed value.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/super.c | 10 ++++++++++
include/linux/fs.h | 2 +-
2 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/fs/super.c b/fs/super.c
index 2761d3e..929d55d 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -889,6 +889,16 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
if (error)
goto out_sb;
+ /*
+ * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
+ * but s_maxbytes was an unsigned long long for many releases. Throw
+ * this warning for a little while to try and catch filesystems that
+ * violate this rule. This warning can be removed in 2.6.34.
+ */
+ WARN(((unsigned long long) mnt->mnt_sb->s_maxbytes > MAX_LFS_FILESIZE),
+ "WARNING: %s sets sb->s_maxbytes too large (%llu)", type->name,
+ (unsigned long long) mnt->mnt_sb->s_maxbytes);
+
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
up_write(&mnt->mnt_sb->s_umount);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a36ffa5..25d9743 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1316,7 +1316,7 @@ struct super_block {
unsigned long s_blocksize;
unsigned char s_blocksize_bits;
unsigned char s_dirt;
- unsigned long long s_maxbytes; /* Max file size */
+ loff_t s_maxbytes; /* Max file size */
struct file_system_type *s_type;
const struct super_operations *s_op;
struct dquot_operations *dq_op;
--
1.6.0.6
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/4] vfs: remove redundant checks in do_sendfile
2009-08-07 18:57 [PATCH 0/4] vfs: change sb->s_maxbytes to loff_t Jeff Layton
` (2 preceding siblings ...)
2009-08-07 18:57 ` [PATCH 3/4] vfs: change sb->s_maxbytes to a loff_t Jeff Layton
@ 2009-08-07 18:57 ` Jeff Layton
2009-08-07 20:58 ` Mandeep Singh Baines
3 siblings, 1 reply; 13+ messages in thread
From: Jeff Layton @ 2009-08-07 18:57 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: akpm, hch, rlove, msb, viro, hannes
As Johannes Weiner pointed out, a couple of the range checks in do_sendfile
are redundant and are already checked in rw_verify_area.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/read_write.c | 11 -----------
1 files changed, 0 insertions(+), 11 deletions(-)
diff --git a/fs/read_write.c b/fs/read_write.c
index 6c8c55d..9c3d98b 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -792,7 +792,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
{
struct file * in_file, * out_file;
struct inode * in_inode, * out_inode;
- loff_t pos;
ssize_t retval;
int fput_needed_in, fput_needed_out, fl;
@@ -838,17 +837,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
if (!max)
max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
- pos = *ppos;
retval = -EINVAL;
- if (unlikely(pos < 0))
- goto fput_out;
- if (unlikely(pos + count > max)) {
- retval = -EOVERFLOW;
- if (pos >= max)
- goto fput_out;
- count = max - pos;
- }
-
fl = 0;
#if 0
/*
--
1.6.0.6
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 3/4] vfs: change sb->s_maxbytes to a loff_t
2009-08-07 18:57 ` [PATCH 3/4] vfs: change sb->s_maxbytes to a loff_t Jeff Layton
@ 2009-08-07 20:14 ` Andreas Dilger
2009-08-07 22:51 ` Johannes Weiner
1 sibling, 0 replies; 13+ messages in thread
From: Andreas Dilger @ 2009-08-07 20:14 UTC (permalink / raw)
To: Jeff Layton
Cc: linux-fsdevel, linux-kernel, akpm, hch, rlove, msb, viro, hannes
On Aug 07, 2009 14:57 -0400, Jeff Layton wrote:
> + /*
> + * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
> + * but s_maxbytes was an unsigned long long for many releases. Throw
> + * this warning for a little while to try and catch filesystems that
> + * violate this rule. This warning can be removed in 2.6.34.
> + */
> + WARN(((unsigned long long) mnt->mnt_sb->s_maxbytes > MAX_LFS_FILESIZE),
> + "WARNING: %s sets sb->s_maxbytes too large (%llu)", type->name,
> + (unsigned long long) mnt->mnt_sb->s_maxbytes);
Rather than removing this check, it should be changed into a BUG_ON() so
that no filesystems are added/modified to get it wrong. We hit this
problem once in the past also...
Cheers, Andreas
--
Andreas Dilger
Sr. Staff Engineer, Lustre Group
Sun Microsystems of Canada, Inc.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 4/4] vfs: remove redundant checks in do_sendfile
2009-08-07 18:57 ` [PATCH 4/4] vfs: remove redundant checks in do_sendfile Jeff Layton
@ 2009-08-07 20:58 ` Mandeep Singh Baines
2009-08-07 21:05 ` Jeff Layton
0 siblings, 1 reply; 13+ messages in thread
From: Mandeep Singh Baines @ 2009-08-07 20:58 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-fsdevel, linux-kernel, akpm, hch, rlove, viro, hannes
Jeff Layton (jlayton@redhat.com) wrote:
> As Johannes Weiner pointed out, a couple of the range checks in do_sendfile
> are redundant and are already checked in rw_verify_area.
>
> Signed-off-by: Jeff Layton <jlayton@redhat.com>
> ---
> fs/read_write.c | 11 -----------
> 1 files changed, 0 insertions(+), 11 deletions(-)
>
> diff --git a/fs/read_write.c b/fs/read_write.c
> index 6c8c55d..9c3d98b 100644
> --- a/fs/read_write.c
> +++ b/fs/read_write.c
> @@ -792,7 +792,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
> {
> struct file * in_file, * out_file;
> struct inode * in_inode, * out_inode;
> - loff_t pos;
> ssize_t retval;
> int fput_needed_in, fput_needed_out, fl;
>
> @@ -838,17 +837,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
> if (!max)
> max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
>
> - pos = *ppos;
> retval = -EINVAL;
> - if (unlikely(pos < 0))
> - goto fput_out;
Agree. This check is redundant.
> - if (unlikely(pos + count > max)) {
rw_verify_area does not check s_maxbytes so aren't the checks against
max still required?
> - retval = -EOVERFLOW;
> - if (pos >= max)
> - goto fput_out;
> - count = max - pos;
> - }
> -
> fl = 0;
> #if 0
> /*
> --
> 1.6.0.6
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 4/4] vfs: remove redundant checks in do_sendfile
2009-08-07 20:58 ` Mandeep Singh Baines
@ 2009-08-07 21:05 ` Jeff Layton
0 siblings, 0 replies; 13+ messages in thread
From: Jeff Layton @ 2009-08-07 21:05 UTC (permalink / raw)
To: Mandeep Singh Baines
Cc: linux-fsdevel, linux-kernel, akpm, hch, rlove, viro, hannes
On Fri, 7 Aug 2009 13:58:33 -0700
Mandeep Singh Baines <msb@google.com> wrote:
> Jeff Layton (jlayton@redhat.com) wrote:
> > As Johannes Weiner pointed out, a couple of the range checks in do_sendfile
> > are redundant and are already checked in rw_verify_area.
> >
> > Signed-off-by: Jeff Layton <jlayton@redhat.com>
> > ---
> > fs/read_write.c | 11 -----------
> > 1 files changed, 0 insertions(+), 11 deletions(-)
> >
> > diff --git a/fs/read_write.c b/fs/read_write.c
> > index 6c8c55d..9c3d98b 100644
> > --- a/fs/read_write.c
> > +++ b/fs/read_write.c
> > @@ -792,7 +792,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
> > {
> > struct file * in_file, * out_file;
> > struct inode * in_inode, * out_inode;
> > - loff_t pos;
> > ssize_t retval;
> > int fput_needed_in, fput_needed_out, fl;
> >
> > @@ -838,17 +837,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
> > if (!max)
> > max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
> >
> > - pos = *ppos;
> > retval = -EINVAL;
> > - if (unlikely(pos < 0))
> > - goto fput_out;
>
> Agree. This check is redundant.
>
> > - if (unlikely(pos + count > max)) {
>
> rw_verify_area does not check s_maxbytes so aren't the checks against
> max still required?
>
Good catch. That's what I get for not touching these patches for a few weeks :)
I'll fix and resend in another day or so.
> > - retval = -EOVERFLOW;
> > - if (pos >= max)
> > - goto fput_out;
> > - count = max - pos;
> > - }
> > -
> > fl = 0;
> > #if 0
> > /*
> > --
> > 1.6.0.6
> >
--
Jeff Layton <jlayton@redhat.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/4] vfs: explicitly cast s_maxbytes in fiemap_check_ranges
2009-08-07 18:57 ` [PATCH 2/4] vfs: explicitly cast s_maxbytes in fiemap_check_ranges Jeff Layton
@ 2009-08-07 22:12 ` Johannes Weiner
2009-08-08 11:20 ` Jeff Layton
0 siblings, 1 reply; 13+ messages in thread
From: Johannes Weiner @ 2009-08-07 22:12 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-fsdevel, linux-kernel, akpm, hch, rlove, msb, viro
On Fri, Aug 07, 2009 at 02:57:39PM -0400, Jeff Layton wrote:
> If fiemap_check_ranges is passed a large enough value, then it's
> possible that the value would be cast to a signed value for comparison
> against s_maxbytes when we change it to loff_t. Make sure that doesn't
> happen by explicitly casting s_maxbytes to an unsigned value for the
> purposes of comparison.
I think this is unneeded, C garuantees that in this case the signed
value will get promoted to an unsigned value, not the other way round.
Hannes
> Signed-off-by: Jeff Layton <jlayton@redhat.com>
> ---
> fs/ioctl.c | 9 +++++----
> 1 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/fs/ioctl.c b/fs/ioctl.c
> index 5612880..7b17a14 100644
> --- a/fs/ioctl.c
> +++ b/fs/ioctl.c
> @@ -162,20 +162,21 @@ EXPORT_SYMBOL(fiemap_check_flags);
> static int fiemap_check_ranges(struct super_block *sb,
> u64 start, u64 len, u64 *new_len)
> {
> + u64 maxbytes = (u64) sb->s_maxbytes;
> +
> *new_len = len;
>
> if (len == 0)
> return -EINVAL;
>
> - if (start > sb->s_maxbytes)
> + if (start > maxbytes)
> return -EFBIG;
>
> /*
> * Shrink request scope to what the fs can actually handle.
> */
> - if ((len > sb->s_maxbytes) ||
> - (sb->s_maxbytes - len) < start)
> - *new_len = sb->s_maxbytes - start;
> + if (len > maxbytes || (maxbytes - len) < start)
> + *new_len = maxbytes - start;
>
> return 0;
> }
> --
> 1.6.0.6
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/4] vfs: make get_sb_pseudo set s_maxbytes to value that can be cast to signed
2009-08-07 18:57 ` [PATCH 1/4] vfs: make get_sb_pseudo set s_maxbytes to value that can be cast to signed Jeff Layton
@ 2009-08-07 22:28 ` Johannes Weiner
0 siblings, 0 replies; 13+ messages in thread
From: Johannes Weiner @ 2009-08-07 22:28 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-fsdevel, linux-kernel, akpm, hch, rlove, msb, viro
On Fri, Aug 07, 2009 at 02:57:38PM -0400, Jeff Layton wrote:
> This patch is a counterpart to the CIFS patch posted yesterday. I
> believe either patch will fix the problem seen in do_sendfile since the
> smaller s_maxbytes value for the two superblocks is used there.
This refers to the 'yesterday' 2-3 weeks ago, no? :-)
> get_sb_pseudo sets s_maxbytes to ~0ULL, which becomes negative when cast
> to a signed value. Fix it to use MAX_LFS_FILESIZE which casts properly
> to a positive signed value.
I think the proper term is 'converted' in this case, not 'cast'. Even
without casts it gets converted by arithmetic operands.
> Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Johannes Weiner <hannes@cmpxchg.org>
> ---
> fs/libfs.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/fs/libfs.c b/fs/libfs.c
> index ddfa899..dcec3d3 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -217,7 +217,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 = PAGE_SIZE;
> s->s_blocksize_bits = PAGE_SHIFT;
> s->s_magic = magic;
> --
> 1.6.0.6
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/4] vfs: change sb->s_maxbytes to a loff_t
2009-08-07 18:57 ` [PATCH 3/4] vfs: change sb->s_maxbytes to a loff_t Jeff Layton
2009-08-07 20:14 ` Andreas Dilger
@ 2009-08-07 22:51 ` Johannes Weiner
2009-08-08 11:15 ` Jeff Layton
1 sibling, 1 reply; 13+ messages in thread
From: Johannes Weiner @ 2009-08-07 22:51 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-fsdevel, linux-kernel, akpm, hch, rlove, msb, viro
On Fri, Aug 07, 2009 at 02:57:40PM -0400, Jeff Layton wrote:
> sb->s_maxbytes is supposed to indicate the maximum size of a file that
> can exist on the filesystem. It's declared as an unsigned long long.
>
> Even if a filesystem has no inherent limit that prevents it from using
> every bit in that unsigned long long, it's still problematic to set it
> to anything larger than MAX_LFS_FILESIZE. A lot of places implicitly
> cast s_maxbytes to a signed value when doing comparisons against it
> (usually using loff_t on the other side of the comparison). If it's
> set too large then this cast makes it a negative number and generally
> breaks the comparison.
>
> Change s_maxbytes to be loff_t instead. That should help eliminate the
> temptation to set it too large by making it a signed value.
>
> Signed-off-by: Jeff Layton <jlayton@redhat.com>
> ---
> fs/super.c | 10 ++++++++++
> include/linux/fs.h | 2 +-
> 2 files changed, 11 insertions(+), 1 deletions(-)
>
> diff --git a/fs/super.c b/fs/super.c
> index 2761d3e..929d55d 100644
> --- a/fs/super.c
> +++ b/fs/super.c
> @@ -889,6 +889,16 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
> if (error)
> goto out_sb;
>
> + /*
> + * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
> + * but s_maxbytes was an unsigned long long for many releases. Throw
> + * this warning for a little while to try and catch filesystems that
> + * violate this rule. This warning can be removed in 2.6.34.
> + */
> + WARN(((unsigned long long) mnt->mnt_sb->s_maxbytes > MAX_LFS_FILESIZE),
> + "WARNING: %s sets sb->s_maxbytes too large (%llu)", type->name,
> + (unsigned long long) mnt->mnt_sb->s_maxbytes);
Since it's signed now, you could just check for it being < 0, no?
I don't like the warning much, though. It seems to be a random check
for a bug that has been fixed now. We don't check other errors from
->get_sb() either.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/4] vfs: change sb->s_maxbytes to a loff_t
2009-08-07 22:51 ` Johannes Weiner
@ 2009-08-08 11:15 ` Jeff Layton
0 siblings, 0 replies; 13+ messages in thread
From: Jeff Layton @ 2009-08-08 11:15 UTC (permalink / raw)
To: Johannes Weiner; +Cc: linux-fsdevel, linux-kernel, akpm, hch, rlove, msb, viro
On Sat, 8 Aug 2009 00:51:46 +0200
Johannes Weiner <hannes@cmpxchg.org> wrote:
> On Fri, Aug 07, 2009 at 02:57:40PM -0400, Jeff Layton wrote:
> > sb->s_maxbytes is supposed to indicate the maximum size of a file that
> > can exist on the filesystem. It's declared as an unsigned long long.
> >
> > Even if a filesystem has no inherent limit that prevents it from using
> > every bit in that unsigned long long, it's still problematic to set it
> > to anything larger than MAX_LFS_FILESIZE. A lot of places implicitly
> > cast s_maxbytes to a signed value when doing comparisons against it
> > (usually using loff_t on the other side of the comparison). If it's
> > set too large then this cast makes it a negative number and generally
> > breaks the comparison.
> >
> > Change s_maxbytes to be loff_t instead. That should help eliminate the
> > temptation to set it too large by making it a signed value.
> >
> > Signed-off-by: Jeff Layton <jlayton@redhat.com>
> > ---
> > fs/super.c | 10 ++++++++++
> > include/linux/fs.h | 2 +-
> > 2 files changed, 11 insertions(+), 1 deletions(-)
> >
> > diff --git a/fs/super.c b/fs/super.c
> > index 2761d3e..929d55d 100644
> > --- a/fs/super.c
> > +++ b/fs/super.c
> > @@ -889,6 +889,16 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
> > if (error)
> > goto out_sb;
> >
> > + /*
> > + * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
> > + * but s_maxbytes was an unsigned long long for many releases. Throw
> > + * this warning for a little while to try and catch filesystems that
> > + * violate this rule. This warning can be removed in 2.6.34.
> > + */
> > + WARN(((unsigned long long) mnt->mnt_sb->s_maxbytes > MAX_LFS_FILESIZE),
> > + "WARNING: %s sets sb->s_maxbytes too large (%llu)", type->name,
> > + (unsigned long long) mnt->mnt_sb->s_maxbytes);
>
> Since it's signed now, you could just check for it being < 0, no?
>
Sure, that works too and is probably a little cleaner. I'll change it
in the next respin to do that.
> I don't like the warning much, though. It seems to be a random check
> for a bug that has been fixed now. We don't check other errors from
> ->get_sb() either.
Ordinarily, I'd agree with this, but we're changing the type of
s_maxbytes. It's possible that:
A) I missed something in one of the more complex s_maxbytes calculations.
B) Out of tree filesystems are broken in this way and don't realize it.
I think it makes some sense to burn a couple of CPU cycles in the mount
codepath for a few releases to try and catch both of these cases. If we
don't warn this way, then this change could result in more subtle
breakage.
--
Jeff Layton <jlayton@redhat.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/4] vfs: explicitly cast s_maxbytes in fiemap_check_ranges
2009-08-07 22:12 ` Johannes Weiner
@ 2009-08-08 11:20 ` Jeff Layton
0 siblings, 0 replies; 13+ messages in thread
From: Jeff Layton @ 2009-08-08 11:20 UTC (permalink / raw)
To: Johannes Weiner; +Cc: linux-fsdevel, linux-kernel, akpm, hch, rlove, msb, viro
On Sat, 8 Aug 2009 00:12:52 +0200
Johannes Weiner <hannes@cmpxchg.org> wrote:
> On Fri, Aug 07, 2009 at 02:57:39PM -0400, Jeff Layton wrote:
> > If fiemap_check_ranges is passed a large enough value, then it's
> > possible that the value would be cast to a signed value for comparison
> > against s_maxbytes when we change it to loff_t. Make sure that doesn't
> > happen by explicitly casting s_maxbytes to an unsigned value for the
> > purposes of comparison.
>
> I think this is unneeded, C garuantees that in this case the signed
> value will get promoted to an unsigned value, not the other way round.
>
After looking at this again, I think you're correct. do_sendfile was
actually casting s_maxbytes to a signed value which is why it was
broken there.
I can drop this patch if the consensus is to do so. I still think
however that it doesn't hurt to do explict casts when comparing signed
and unsigned values to remove any potential for ambiguity.
--
Jeff Layton <jlayton@redhat.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2009-08-08 11:20 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-07 18:57 [PATCH 0/4] vfs: change sb->s_maxbytes to loff_t Jeff Layton
2009-08-07 18:57 ` [PATCH 1/4] vfs: make get_sb_pseudo set s_maxbytes to value that can be cast to signed Jeff Layton
2009-08-07 22:28 ` Johannes Weiner
2009-08-07 18:57 ` [PATCH 2/4] vfs: explicitly cast s_maxbytes in fiemap_check_ranges Jeff Layton
2009-08-07 22:12 ` Johannes Weiner
2009-08-08 11:20 ` Jeff Layton
2009-08-07 18:57 ` [PATCH 3/4] vfs: change sb->s_maxbytes to a loff_t Jeff Layton
2009-08-07 20:14 ` Andreas Dilger
2009-08-07 22:51 ` Johannes Weiner
2009-08-08 11:15 ` Jeff Layton
2009-08-07 18:57 ` [PATCH 4/4] vfs: remove redundant checks in do_sendfile Jeff Layton
2009-08-07 20:58 ` Mandeep Singh Baines
2009-08-07 21:05 ` Jeff Layton
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.