[Ocfs2-devel] [PATCH] ocfs2: avoid unaligned access to dqc_bitmap

Joel Becker jlbec at evilplan.org
Wed Feb 9 09:05:08 PST 2011


On Wed, Feb 02, 2011 at 06:31:59PM +0900, Akinobu Mita wrote:
> The dqc_bitmap field of struct ocfs2_local_disk_chunk is 32-bit aligned,
> but not 64-bit aligned. The dqc_bitmap is accessed by ocfs2_set_bit(),
> ocfs2_clear_bit(), ocfs2_test_bit(), or ocfs2_find_next_zero_bit().
> These are wrapper macros for ext2_*_bit() which need to take an unsigned
> long aligned address (though some architectures are able to handle
> unaligned address correctly)
> 
> So some 64bit architectures may not be able to access the dqc_bitmap
> correctly.
> 
> This avoids such unaligned access by using another wrapper functions for
> ext2_*_bit().  The code is taken from fs/ext4/mballoc.c which also need
> to handle unaligned bitmap access.
> 
> Signed-off-by: Akinobu Mita <akinobu.mita at gmail.com>
> Cc: Mark Fasheh <mfasheh at suse.com>
> Cc: Joel Becker <jlbec at evilplan.org>
> Cc: ocfs2-devel at oss.oracle.com

Acked-by: Joel Becker <jlbec at evilplan.org>

> ---
> 
> I'm not sure if any 64bit architectures hit this problem.  It was found
> by code inspection while I was working on the little-endian bitops
> patch series.
> 
>  fs/ocfs2/ocfs2.h       |   47 +++++++++++++++++++++++++++++++++++++++++++++++
>  fs/ocfs2/quota_local.c |   10 +++++-----
>  2 files changed, 52 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
> index 51cd689..4e4581e 100644
> --- a/fs/ocfs2/ocfs2.h
> +++ b/fs/ocfs2/ocfs2.h
> @@ -844,5 +844,52 @@ static inline void _ocfs2_clear_bit(unsigned int bit, unsigned long *bitmap)
>  #define ocfs2_test_bit ext2_test_bit
>  #define ocfs2_find_next_zero_bit ext2_find_next_zero_bit
>  #define ocfs2_find_next_bit ext2_find_next_bit
> +
> +static inline void *correct_addr_and_bit_unaligned(int *bit, void *addr)
> +{
> +#if BITS_PER_LONG == 64
> +	*bit += ((unsigned long) addr & 7UL) << 3;
> +	addr = (void *) ((unsigned long) addr & ~7UL);
> +#elif BITS_PER_LONG == 32
> +	*bit += ((unsigned long) addr & 3UL) << 3;
> +	addr = (void *) ((unsigned long) addr & ~3UL);
> +#else
> +#error "how many bits you are?!"
> +#endif
> +	return addr;
> +}
> +
> +static inline void ocfs2_set_bit_unaligned(int bit, void *bitmap)
> +{
> +	bitmap = correct_addr_and_bit_unaligned(&bit, bitmap);
> +	ocfs2_set_bit(bit, bitmap);
> +}
> +
> +static inline void ocfs2_clear_bit_unaligned(int bit, void *bitmap)
> +{
> +	bitmap = correct_addr_and_bit_unaligned(&bit, bitmap);
> +	ocfs2_clear_bit(bit, bitmap);
> +}
> +
> +static inline int ocfs2_test_bit_unaligned(int bit, void *bitmap)
> +{
> +	bitmap = correct_addr_and_bit_unaligned(&bit, bitmap);
> +	return ocfs2_test_bit(bit, bitmap);
> +}
> +
> +static inline int ocfs2_find_next_zero_bit_unaligned(void *bitmap, int max,
> +							int start)
> +{
> +	int fix = 0, ret, tmpmax;
> +	bitmap = correct_addr_and_bit_unaligned(&fix, bitmap);
> +	tmpmax = max + fix;
> +	start += fix;
> +
> +	ret = ocfs2_find_next_zero_bit(bitmap, tmpmax, start) - fix;
> +	if (ret > max)
> +		return max;
> +	return ret;
> +}
> +
>  #endif  /* OCFS2_H */
>  
> diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
> index dc78764..1290423 100644
> --- a/fs/ocfs2/quota_local.c
> +++ b/fs/ocfs2/quota_local.c
> @@ -549,8 +549,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
>  				goto out_commit;
>  			}
>  			lock_buffer(qbh);
> -			WARN_ON(!ocfs2_test_bit(bit, dchunk->dqc_bitmap));
> -			ocfs2_clear_bit(bit, dchunk->dqc_bitmap);
> +			WARN_ON(!ocfs2_test_bit_unaligned(bit, dchunk->dqc_bitmap));
> +			ocfs2_clear_bit_unaligned(bit, dchunk->dqc_bitmap);
>  			le32_add_cpu(&dchunk->dqc_free, 1);
>  			unlock_buffer(qbh);
>  			ocfs2_journal_dirty(handle, qbh);
> @@ -942,7 +942,7 @@ static struct ocfs2_quota_chunk *ocfs2_find_free_entry(struct super_block *sb,
>  		      * ol_quota_entries_per_block(sb);
>  	}
>  
> -	found = ocfs2_find_next_zero_bit(dchunk->dqc_bitmap, len, 0);
> +	found = ocfs2_find_next_zero_bit_unaligned(dchunk->dqc_bitmap, len, 0);
>  	/* We failed? */
>  	if (found == len) {
>  		mlog(ML_ERROR, "Did not find empty entry in chunk %d with %u"
> @@ -1206,7 +1206,7 @@ static void olq_alloc_dquot(struct buffer_head *bh, void *private)
>  	struct ocfs2_local_disk_chunk *dchunk;
>  
>  	dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
> -	ocfs2_set_bit(*offset, dchunk->dqc_bitmap);
> +	ocfs2_set_bit_unaligned(*offset, dchunk->dqc_bitmap);
>  	le32_add_cpu(&dchunk->dqc_free, -1);
>  }
>  
> @@ -1287,7 +1287,7 @@ int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
>  			(od->dq_chunk->qc_headerbh->b_data);
>  	/* Mark structure as freed */
>  	lock_buffer(od->dq_chunk->qc_headerbh);
> -	ocfs2_clear_bit(offset, dchunk->dqc_bitmap);
> +	ocfs2_clear_bit_unaligned(offset, dchunk->dqc_bitmap);
>  	le32_add_cpu(&dchunk->dqc_free, 1);
>  	unlock_buffer(od->dq_chunk->qc_headerbh);
>  	ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
> -- 
> 1.7.3.3
> 

-- 

"Lately I've been talking in my sleep.
 Can't imagine what I'd have to say.
 Except my world will be right
 When love comes back my way."

			http://www.jlbec.org/
			jlbec at evilplan.org



More information about the Ocfs2-devel mailing list