diff mbox

[Ocfs2-devel,1/3] ext3/ext4: Factor out disk addressability check

Message ID 20100812222949.GC22777@mail.oracle.com
State Accepted, archived
Headers show

Commit Message

Joel Becker Aug. 12, 2010, 10:29 p.m. UTC
On Thu, Aug 12, 2010 at 03:32:27PM -0600, Andreas Dilger wrote:
> > 	If I change the BUG_ON()s to -EINVAL, does that work?  Or do you
> > have some way you'd like to allow non-pagecache filesystems to use this
> > as well?
> 
> That's probably fine for now.  If anyone complains, we can always change it later, since they can't possibly depend on this function yet...

	How's this:

>From f988b04c58039ae9a65fea537656088ea56a8072 Mon Sep 17 00:00:00 2001
>From: Patrick J. LoPresti <lopresti@gmail.com>
Date: Thu, 22 Jul 2010 15:03:41 -0700
Subject: [PATCH] ext3/ext4: Factor out disk addressability check

As part of adding support for OCFS2 to mount huge volumes, we need to
check that the sector_t and page cache of the system are capable of
addressing the entire volume.

An identical check already appears in ext3 and ext4.  This patch moves
the addressability check into its own function in fs/libfs.c and
modifies ext3 and ext4 to invoke it.

[Edited to -EINVAL instead of BUG_ON() for bad blocksize_bits -- Joel]

Signed-off-by: Patrick LoPresti <lopresti@gmail.com>
Cc: linux-ext4@vger.kernel.org
Signed-off-by: Joel Becker <joel.becker@oracle.com>
---
 fs/ext3/super.c    |    4 ++--
 fs/ext4/super.c    |    8 +++-----
 fs/libfs.c         |   29 +++++++++++++++++++++++++++++
 include/linux/fs.h |    2 ++
 4 files changed, 36 insertions(+), 7 deletions(-)

Comments

Andreas Dilger Aug. 12, 2010, 11:07 p.m. UTC | #1
You can add my:

Acked-by: Andreas Dilger <adilger@dilger.ca>

On 2010-08-12, at 16:29, Joel Becker wrote:

> On Thu, Aug 12, 2010 at 03:32:27PM -0600, Andreas Dilger wrote:
>>> 	If I change the BUG_ON()s to -EINVAL, does that work?  Or do you
>>> have some way you'd like to allow non-pagecache filesystems to use this
>>> as well?
>> 
>> That's probably fine for now.  If anyone complains, we can always change it later, since they can't possibly depend on this function yet...
> 
> 	How's this:
> 
>> From f988b04c58039ae9a65fea537656088ea56a8072 Mon Sep 17 00:00:00 2001
>> From: Patrick J. LoPresti <lopresti@gmail.com>
> Date: Thu, 22 Jul 2010 15:03:41 -0700
> Subject: [PATCH] ext3/ext4: Factor out disk addressability check
> 
> As part of adding support for OCFS2 to mount huge volumes, we need to
> check that the sector_t and page cache of the system are capable of
> addressing the entire volume.
> 
> An identical check already appears in ext3 and ext4.  This patch moves
> the addressability check into its own function in fs/libfs.c and
> modifies ext3 and ext4 to invoke it.
> 
> [Edited to -EINVAL instead of BUG_ON() for bad blocksize_bits -- Joel]
> 
> Signed-off-by: Patrick LoPresti <lopresti@gmail.com>
> Cc: linux-ext4@vger.kernel.org
> Signed-off-by: Joel Becker <joel.becker@oracle.com>
> ---
> fs/ext3/super.c    |    4 ++--
> fs/ext4/super.c    |    8 +++-----
> fs/libfs.c         |   29 +++++++++++++++++++++++++++++
> include/linux/fs.h |    2 ++
> 4 files changed, 36 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/ext3/super.c b/fs/ext3/super.c
> index 6c953bb..d0643db 100644
> --- a/fs/ext3/super.c
> +++ b/fs/ext3/super.c
> @@ -1862,8 +1862,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
> 		goto failed_mount;
> 	}
> 
> -	if (le32_to_cpu(es->s_blocks_count) >
> -		    (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
> +	if (generic_check_addressable(sb->s_blocksize_bits,
> +				      le32_to_cpu(es->s_blocks_count))) {
> 		ext3_msg(sb, KERN_ERR,
> 			"error: filesystem is too large to mount safely");
> 		if (sizeof(sector_t) < 8)
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index e72d323..e03a7d2 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -2706,15 +2706,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> 	 * Test whether we have more sectors than will fit in sector_t,
> 	 * and whether the max offset is addressable by the page cache.
> 	 */
> -	if ((ext4_blocks_count(es) >
> -	     (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) ||
> -	    (ext4_blocks_count(es) >
> -	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits))) {
> +	ret = generic_check_addressable(sb->s_blocksize_bits,
> +					ext4_blocks_count(es));
> +	if (ret) {
> 		ext4_msg(sb, KERN_ERR, "filesystem"
> 			 " too large to mount safely on this system");
> 		if (sizeof(sector_t) < 8)
> 			ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled");
> -		ret = -EFBIG;
> 		goto failed_mount;
> 	}
> 
> diff --git a/fs/libfs.c b/fs/libfs.c
> index dcaf972..f099566 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -955,6 +955,35 @@ int generic_file_fsync(struct file *file, int datasync)
> }
> EXPORT_SYMBOL(generic_file_fsync);
> 
> +/**
> + * generic_check_addressable - Check addressability of file system
> + * @blocksize_bits:	log of file system block size
> + * @num_blocks:		number of blocks in file system
> + *
> + * Determine whether a file system with @num_blocks blocks (and a
> + * block size of 2**@blocksize_bits) is addressable by the sector_t
> + * and page cache of the system.  Return 0 if so and -EFBIG otherwise.
> + */
> +int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks)
> +{
> +	u64 last_fs_block = num_blocks - 1;
> +
> +	if (unlikely(num_blocks == 0))
> +		return 0;
> +
> +	if ((blocksize_bits < 9) || (blocksize_bits > PAGE_CACHE_SHIFT))
> +		return -EINVAL;
> +
> +	if ((last_fs_block >
> +	     (sector_t)(~0ULL) >> (blocksize_bits - 9)) ||
> +	    (last_fs_block >
> +	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) {
> +		return -EFBIG;
> +	}
> +	return 0;
> +}
> +EXPORT_SYMBOL(generic_check_addressable);
> +
> /*
>  * No-op implementation of ->fsync for in-memory filesystems.
>  */
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index e5106e4..7644248 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2414,6 +2414,8 @@ extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
> 
> extern int generic_file_fsync(struct file *, int);
> 
> +extern int generic_check_addressable(unsigned, u64);
> +
> #ifdef CONFIG_MIGRATION
> extern int buffer_migrate_page(struct address_space *,
> 				struct page *, struct page *);
> -- 
> 1.7.1
> 
> 
> -- 
> 
> "Friends may come and go, but enemies accumulate." 
>        - Thomas Jones
> 
> Joel Becker
> Consulting Software Developer
> Oracle
> E-mail: joel.becker@oracle.com
> Phone: (650) 506-8127
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


Cheers, Andreas





--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joel Becker Aug. 12, 2010, 11:13 p.m. UTC | #2
On Thu, Aug 12, 2010 at 05:07:36PM -0600, Andreas Dilger wrote:
> You can add my:
> 
> Acked-by: Andreas Dilger <adilger@dilger.ca>

	Thanks!

Joel
Jan Kara Aug. 13, 2010, 4:30 p.m. UTC | #3
On Thu 12-08-10 15:29:49, Joel Becker wrote:
> diff --git a/fs/libfs.c b/fs/libfs.c
> index dcaf972..f099566 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -955,6 +955,35 @@ int generic_file_fsync(struct file *file, int datasync)
>  }
>  EXPORT_SYMBOL(generic_file_fsync);
>  
> +/**
> + * generic_check_addressable - Check addressability of file system
> + * @blocksize_bits:	log of file system block size
> + * @num_blocks:		number of blocks in file system
> + *
> + * Determine whether a file system with @num_blocks blocks (and a
> + * block size of 2**@blocksize_bits) is addressable by the sector_t
> + * and page cache of the system.  Return 0 if so and -EFBIG otherwise.
> + */
> +int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks)
> +{
> +	u64 last_fs_block = num_blocks - 1;
> +
> +	if (unlikely(num_blocks == 0))
> +		return 0;
> +
> +	if ((blocksize_bits < 9) || (blocksize_bits > PAGE_CACHE_SHIFT))
> +		return -EINVAL;
> +
> +	if ((last_fs_block >
> +	     (sector_t)(~0ULL) >> (blocksize_bits - 9)) ||
> +	    (last_fs_block >
> +	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) {
            ^^^ I don't get the pgoff_t check. Shouldn't it rather be
(u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)?
Because on 32-bit arch we are able to address 16TB device, which is for 1KB
blocksize 1<<34 blocks. But your math gives 1<<30 blocks...

									Honza
Joel Becker Aug. 13, 2010, 8:47 p.m. UTC | #4
On Fri, Aug 13, 2010 at 06:30:07PM +0200, Jan Kara wrote:
> On Thu 12-08-10 15:29:49, Joel Becker wrote:
> > +/**
> > + * generic_check_addressable - Check addressability of file system
> > + * @blocksize_bits:	log of file system block size
> > + * @num_blocks:		number of blocks in file system
> > + *
> > + * Determine whether a file system with @num_blocks blocks (and a
> > + * block size of 2**@blocksize_bits) is addressable by the sector_t
> > + * and page cache of the system.  Return 0 if so and -EFBIG otherwise.
> > + */
> > +int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks)
> > +{
> > +	u64 last_fs_block = num_blocks - 1;
> > +
> > +	if (unlikely(num_blocks == 0))
> > +		return 0;
> > +
> > +	if ((blocksize_bits < 9) || (blocksize_bits > PAGE_CACHE_SHIFT))
> > +		return -EINVAL;
> > +
> > +	if ((last_fs_block >
> > +	     (sector_t)(~0ULL) >> (blocksize_bits - 9)) ||
> > +	    (last_fs_block >
> > +	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) {
>             ^^^ I don't get the pgoff_t check. Shouldn't it rather be
> (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)?
> Because on 32-bit arch we are able to address 16TB device, which is for 1KB
> blocksize 1<<34 blocks. But your math gives 1<<30 blocks...

	This code is directly lifted from ext4.  But that said, I am
starting to think you're right.  1 page == 4 x 1K blocks, rather than 4
pages == 1 1K block.

Joel
Joel Becker Aug. 13, 2010, 10:52 p.m. UTC | #5
On Fri, Aug 13, 2010 at 01:47:01PM -0700, Joel Becker wrote:
> On Fri, Aug 13, 2010 at 06:30:07PM +0200, Jan Kara wrote:
> > On Thu 12-08-10 15:29:49, Joel Becker wrote:
> > > +/**
> > > + * generic_check_addressable - Check addressability of file system
> > > + * @blocksize_bits:	log of file system block size
> > > + * @num_blocks:		number of blocks in file system
> > > + *
> > > + * Determine whether a file system with @num_blocks blocks (and a
> > > + * block size of 2**@blocksize_bits) is addressable by the sector_t
> > > + * and page cache of the system.  Return 0 if so and -EFBIG otherwise.
> > > + */
> > > +int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks)
> > > +{
> > > +	u64 last_fs_block = num_blocks - 1;
> > > +
> > > +	if (unlikely(num_blocks == 0))
> > > +		return 0;
> > > +
> > > +	if ((blocksize_bits < 9) || (blocksize_bits > PAGE_CACHE_SHIFT))
> > > +		return -EINVAL;
> > > +
> > > +	if ((last_fs_block >
> > > +	     (sector_t)(~0ULL) >> (blocksize_bits - 9)) ||
> > > +	    (last_fs_block >
> > > +	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) {
> >             ^^^ I don't get the pgoff_t check. Shouldn't it rather be
> > (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)?
> > Because on 32-bit arch we are able to address 16TB device, which is for 1KB
> > blocksize 1<<34 blocks. But your math gives 1<<30 blocks...
> 
> 	This code is directly lifted from ext4.  But that said, I am
> starting to think you're right.  1 page == 4 x 1K blocks, rather than 4
> pages == 1 1K block.

	Wouldn't it rather be:

	    ... ||
	    ((last_fs_block >> (PAGE_CACHE_SHIFT - blocksize_bits)) >
	     (pgoff_t)(!0ULL))) {

Joel
Eric Sandeen Aug. 15, 2010, 5:19 p.m. UTC | #6
Jan Kara wrote:
> On Thu 12-08-10 15:29:49, Joel Becker wrote:
>> diff --git a/fs/libfs.c b/fs/libfs.c
>> index dcaf972..f099566 100644
>> --- a/fs/libfs.c
>> +++ b/fs/libfs.c
>> @@ -955,6 +955,35 @@ int generic_file_fsync(struct file *file, int datasync)
>>  }
>>  EXPORT_SYMBOL(generic_file_fsync);
>>  
>> +/**
>> + * generic_check_addressable - Check addressability of file system
>> + * @blocksize_bits:	log of file system block size
>> + * @num_blocks:		number of blocks in file system
>> + *
>> + * Determine whether a file system with @num_blocks blocks (and a
>> + * block size of 2**@blocksize_bits) is addressable by the sector_t
>> + * and page cache of the system.  Return 0 if so and -EFBIG otherwise.
>> + */
>> +int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks)
>> +{
>> +	u64 last_fs_block = num_blocks - 1;
>> +
>> +	if (unlikely(num_blocks == 0))
>> +		return 0;
>> +
>> +	if ((blocksize_bits < 9) || (blocksize_bits > PAGE_CACHE_SHIFT))
>> +		return -EINVAL;
>> +
>> +	if ((last_fs_block >
>> +	     (sector_t)(~0ULL) >> (blocksize_bits - 9)) ||
>> +	    (last_fs_block >
>> +	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) {
>             ^^^ I don't get the pgoff_t check. Shouldn't it rather be
> (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)?

Argh that was my fault...  Thankfully not too many 1k-blocksize-formatted
16T devices out there, I guess.

I went through the math again and also came up with:

total fs pages is blocks / (blocks per page)
total pages is blocks / (1 << PAGE_CACHE_SHIFT / 1 << blocksize_bits)
total pages is blocks / (1 << (PAGE_CACHE_SHIFT - blocksize_bits))
total pages is blocks * (1 >> (PAGE_CACHE_SHIFT - blocksize_bits))
total pages is blocks >> (PAGE_CACHE_SHIFT - blocksize_bits)

too big if total pages is > (pgoff_t)(~0ULL)
too big if blocks >> (PAGE_CACHE_SHIFT - blocksize_bits) > (pgoff_t)(~0ULL)
too big if blocks > (pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)
and to not overflow:
too big if blocks > (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)

so seems like the test is:

last_fs_block > (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)

Given the density of the logic in the helper it seems like maybe breaking it
up and adding specific comments might be helpful to the reader:

	/* can IO layers fit total fs sectors in a sector_t? */
	if (last_fs_block >
	    (sector_t)(~0ULL) >> (blocksize_bits - 9))
		return -EFBIG;

	/* can page cache fit total fs pages in a pgoff_t? */
	if (last_fs_block >
	    (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)
		return -EFBIG;

Or something like that.

Sorry for chiming in late...

-Eric

> Because on 32-bit arch we are able to address 16TB device, which is for 1KB
> blocksize 1<<34 blocks. But your math gives 1<<30 blocks...
> 
> 									Honza
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joel Becker Aug. 16, 2010, 2:54 a.m. UTC | #7
On Sun, Aug 15, 2010 at 12:19:36PM -0500, Eric Sandeen wrote:
> >> +	    (last_fs_block >
> >> +	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) {
> >             ^^^ I don't get the pgoff_t check. Shouldn't it rather be
> > (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)?
> 
> Argh that was my fault...  Thankfully not too many 1k-blocksize-formatted
> 16T devices out there, I guess.
> 
> I went through the math again and also came up with:
> 
> total fs pages is blocks / (blocks per page)
> total pages is blocks / (1 << PAGE_CACHE_SHIFT / 1 << blocksize_bits)
> total pages is blocks / (1 << (PAGE_CACHE_SHIFT - blocksize_bits))
> total pages is blocks * (1 >> (PAGE_CACHE_SHIFT - blocksize_bits))
> total pages is blocks >> (PAGE_CACHE_SHIFT - blocksize_bits)
> 
> too big if total pages is > (pgoff_t)(~0ULL)
> too big if blocks >> (PAGE_CACHE_SHIFT - blocksize_bits) > (pgoff_t)(~0ULL)

	Why not stop here, which is what I put in my other email?
"blocks >> SHIFT-bits" is "how many pages do I need?".

> too big if blocks > (pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)
> and to not overflow:
> too big if blocks > (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)

	This still overflows.  pgoff_t is a u64 on 64bit machines,
right?  So shift that left by anything and you wrap.

Joel
Eric Sandeen Aug. 16, 2010, 3:36 a.m. UTC | #8
Joel Becker wrote:
> On Sun, Aug 15, 2010 at 12:19:36PM -0500, Eric Sandeen wrote:
>>>> +	    (last_fs_block >
>>>> +	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) {
>>>             ^^^ I don't get the pgoff_t check. Shouldn't it rather be
>>> (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)?
>> Argh that was my fault...  Thankfully not too many 1k-blocksize-formatted
>> 16T devices out there, I guess.
>>
>> I went through the math again and also came up with:
>>
>> total fs pages is blocks / (blocks per page)
>> total pages is blocks / (1 << PAGE_CACHE_SHIFT / 1 << blocksize_bits)
>> total pages is blocks / (1 << (PAGE_CACHE_SHIFT - blocksize_bits))
>> total pages is blocks * (1 >> (PAGE_CACHE_SHIFT - blocksize_bits))
>> total pages is blocks >> (PAGE_CACHE_SHIFT - blocksize_bits)
>>
>> too big if total pages is > (pgoff_t)(~0ULL)
>> too big if blocks >> (PAGE_CACHE_SHIFT - blocksize_bits) > (pgoff_t)(~0ULL)
> 
> 	Why not stop here, which is what I put in my other email?
> "blocks >> SHIFT-bits" is "how many pages do I need?".

yeah, ok.  Was going for pointless symmetry w/ the other test...

>> too big if blocks > (pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)
>> and to not overflow:
>> too big if blocks > (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)
> 
> 	This still overflows.  pgoff_t is a u64 on 64bit machines,
> right?  So shift that left by anything and you wrap.

Er, yeah.  I had 32 bits in my head since that's the case we're
checking for... whoops.

So I guess your

 	    ... ||
	    ((last_fs_block >> (PAGE_CACHE_SHIFT - blocksize_bits)) >
	     (pgoff_t)(!0ULL))) {

is right :)  (my feeble brain has a hard time reading that, though, TBH)

-Eric

> Joel
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joel Becker Aug. 16, 2010, 9:21 a.m. UTC | #9
On Sun, Aug 15, 2010 at 10:36:36PM -0500, Eric Sandeen wrote:
> Er, yeah.  I had 32 bits in my head since that's the case we're
> checking for... whoops.
> 
> So I guess your
> 
>  	    ... ||
> 	    ((last_fs_block >> (PAGE_CACHE_SHIFT - blocksize_bits)) >
> 	     (pgoff_t)(!0ULL))) {
> 
> is right :)  (my feeble brain has a hard time reading that, though, TBH)

	Well, note the bug in my quickly typed version: "(!0ULL)" vs
"(~0ULL)".  How about:

	u64 last_fs_page = last_fs_block >> (PAGE_CACHE_SHIFT - blocksize_bits);

	... ||
	(last_fs_page > (pgoff_t)(~0ULL))) {

Is that more readable?

Joel
Eric Sandeen Aug. 16, 2010, 2:44 p.m. UTC | #10
Joel Becker wrote:
> On Sun, Aug 15, 2010 at 10:36:36PM -0500, Eric Sandeen wrote:
>> Er, yeah.  I had 32 bits in my head since that's the case we're
>> checking for... whoops.
>>
>> So I guess your
>>
>>  	    ... ||
>> 	    ((last_fs_block >> (PAGE_CACHE_SHIFT - blocksize_bits)) >
>> 	     (pgoff_t)(!0ULL))) {
>>
>> is right :)  (my feeble brain has a hard time reading that, though, TBH)
> 
> 	Well, note the bug in my quickly typed version: "(!0ULL)" vs
> "(~0ULL)".  

*nod* saw that but figured it was just a typo & didn't mention it ;)

> How about:
> 
> 	u64 last_fs_page = last_fs_block >> (PAGE_CACHE_SHIFT - blocksize_bits);
> 
> 	... ||
> 	(last_fs_page > (pgoff_t)(~0ULL))) {
> 
> Is that more readable?

To me, yes.  Maybe do similar for last_fs_sector.

If it's getting too verbose I understand, but less dense is a lot easier
to read, IMHO.  Just style though, really, so *shrug*

Thanks,
-Eric

> Joel
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jan Kara Aug. 16, 2010, 3:09 p.m. UTC | #11
On Fri 13-08-10 15:52:46, Joel Becker wrote:
> On Fri, Aug 13, 2010 at 01:47:01PM -0700, Joel Becker wrote:
> > On Fri, Aug 13, 2010 at 06:30:07PM +0200, Jan Kara wrote:
> > > On Thu 12-08-10 15:29:49, Joel Becker wrote:
> > > > +/**
> > > > + * generic_check_addressable - Check addressability of file system
> > > > + * @blocksize_bits:	log of file system block size
> > > > + * @num_blocks:		number of blocks in file system
> > > > + *
> > > > + * Determine whether a file system with @num_blocks blocks (and a
> > > > + * block size of 2**@blocksize_bits) is addressable by the sector_t
> > > > + * and page cache of the system.  Return 0 if so and -EFBIG otherwise.
> > > > + */
> > > > +int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks)
> > > > +{
> > > > +	u64 last_fs_block = num_blocks - 1;
> > > > +
> > > > +	if (unlikely(num_blocks == 0))
> > > > +		return 0;
> > > > +
> > > > +	if ((blocksize_bits < 9) || (blocksize_bits > PAGE_CACHE_SHIFT))
> > > > +		return -EINVAL;
> > > > +
> > > > +	if ((last_fs_block >
> > > > +	     (sector_t)(~0ULL) >> (blocksize_bits - 9)) ||
> > > > +	    (last_fs_block >
> > > > +	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) {
> > >             ^^^ I don't get the pgoff_t check. Shouldn't it rather be
> > > (u64)(pgoff_t)(~0ULL) << (PAGE_CACHE_SHIFT - blocksize_bits)?
> > > Because on 32-bit arch we are able to address 16TB device, which is for 1KB
> > > blocksize 1<<34 blocks. But your math gives 1<<30 blocks...
> > 
> > 	This code is directly lifted from ext4.  But that said, I am
> > starting to think you're right.  1 page == 4 x 1K blocks, rather than 4
> > pages == 1 1K block.
> 
> 	Wouldn't it rather be:
> 
> 	    ... ||
> 	    ((last_fs_block >> (PAGE_CACHE_SHIFT - blocksize_bits)) >
> 	     (pgoff_t)(!0ULL))) {
  Yes, this would be even better than what I suggested.

								Honza
diff mbox

Patch

diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 6c953bb..d0643db 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -1862,8 +1862,8 @@  static int ext3_fill_super (struct super_block *sb, void *data, int silent)
 		goto failed_mount;
 	}
 
-	if (le32_to_cpu(es->s_blocks_count) >
-		    (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+	if (generic_check_addressable(sb->s_blocksize_bits,
+				      le32_to_cpu(es->s_blocks_count))) {
 		ext3_msg(sb, KERN_ERR,
 			"error: filesystem is too large to mount safely");
 		if (sizeof(sector_t) < 8)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index e72d323..e03a7d2 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -2706,15 +2706,13 @@  static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 	 * Test whether we have more sectors than will fit in sector_t,
 	 * and whether the max offset is addressable by the page cache.
 	 */
-	if ((ext4_blocks_count(es) >
-	     (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) ||
-	    (ext4_blocks_count(es) >
-	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits))) {
+	ret = generic_check_addressable(sb->s_blocksize_bits,
+					ext4_blocks_count(es));
+	if (ret) {
 		ext4_msg(sb, KERN_ERR, "filesystem"
 			 " too large to mount safely on this system");
 		if (sizeof(sector_t) < 8)
 			ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled");
-		ret = -EFBIG;
 		goto failed_mount;
 	}
 
diff --git a/fs/libfs.c b/fs/libfs.c
index dcaf972..f099566 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -955,6 +955,35 @@  int generic_file_fsync(struct file *file, int datasync)
 }
 EXPORT_SYMBOL(generic_file_fsync);
 
+/**
+ * generic_check_addressable - Check addressability of file system
+ * @blocksize_bits:	log of file system block size
+ * @num_blocks:		number of blocks in file system
+ *
+ * Determine whether a file system with @num_blocks blocks (and a
+ * block size of 2**@blocksize_bits) is addressable by the sector_t
+ * and page cache of the system.  Return 0 if so and -EFBIG otherwise.
+ */
+int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks)
+{
+	u64 last_fs_block = num_blocks - 1;
+
+	if (unlikely(num_blocks == 0))
+		return 0;
+
+	if ((blocksize_bits < 9) || (blocksize_bits > PAGE_CACHE_SHIFT))
+		return -EINVAL;
+
+	if ((last_fs_block >
+	     (sector_t)(~0ULL) >> (blocksize_bits - 9)) ||
+	    (last_fs_block >
+	     (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) {
+		return -EFBIG;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(generic_check_addressable);
+
 /*
  * No-op implementation of ->fsync for in-memory filesystems.
  */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e5106e4..7644248 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2414,6 +2414,8 @@  extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
 
 extern int generic_file_fsync(struct file *, int);
 
+extern int generic_check_addressable(unsigned, u64);
+
 #ifdef CONFIG_MIGRATION
 extern int buffer_migrate_page(struct address_space *,
 				struct page *, struct page *);