Skip to content

Commit 9392557

Browse files
mitajlbec
authored andcommitted
ocfs2: avoid unaligned access to dqc_bitmap
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 <[email protected]> Acked-by: Joel Becker <[email protected]> Cc: Mark Fasheh <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Joel Becker <[email protected]>
1 parent 249ec93 commit 9392557

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

fs/ocfs2/ocfs2.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,5 +849,52 @@ static inline void _ocfs2_clear_bit(unsigned int bit, unsigned long *bitmap)
849849
#define ocfs2_test_bit test_bit_le
850850
#define ocfs2_find_next_zero_bit find_next_zero_bit_le
851851
#define ocfs2_find_next_bit find_next_bit_le
852+
853+
static inline void *correct_addr_and_bit_unaligned(int *bit, void *addr)
854+
{
855+
#if BITS_PER_LONG == 64
856+
*bit += ((unsigned long) addr & 7UL) << 3;
857+
addr = (void *) ((unsigned long) addr & ~7UL);
858+
#elif BITS_PER_LONG == 32
859+
*bit += ((unsigned long) addr & 3UL) << 3;
860+
addr = (void *) ((unsigned long) addr & ~3UL);
861+
#else
862+
#error "how many bits you are?!"
863+
#endif
864+
return addr;
865+
}
866+
867+
static inline void ocfs2_set_bit_unaligned(int bit, void *bitmap)
868+
{
869+
bitmap = correct_addr_and_bit_unaligned(&bit, bitmap);
870+
ocfs2_set_bit(bit, bitmap);
871+
}
872+
873+
static inline void ocfs2_clear_bit_unaligned(int bit, void *bitmap)
874+
{
875+
bitmap = correct_addr_and_bit_unaligned(&bit, bitmap);
876+
ocfs2_clear_bit(bit, bitmap);
877+
}
878+
879+
static inline int ocfs2_test_bit_unaligned(int bit, void *bitmap)
880+
{
881+
bitmap = correct_addr_and_bit_unaligned(&bit, bitmap);
882+
return ocfs2_test_bit(bit, bitmap);
883+
}
884+
885+
static inline int ocfs2_find_next_zero_bit_unaligned(void *bitmap, int max,
886+
int start)
887+
{
888+
int fix = 0, ret, tmpmax;
889+
bitmap = correct_addr_and_bit_unaligned(&fix, bitmap);
890+
tmpmax = max + fix;
891+
start += fix;
892+
893+
ret = ocfs2_find_next_zero_bit(bitmap, tmpmax, start) - fix;
894+
if (ret > max)
895+
return max;
896+
return ret;
897+
}
898+
852899
#endif /* OCFS2_H */
853900

fs/ocfs2/quota_local.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
551551
goto out_commit;
552552
}
553553
lock_buffer(qbh);
554-
WARN_ON(!ocfs2_test_bit(bit, dchunk->dqc_bitmap));
555-
ocfs2_clear_bit(bit, dchunk->dqc_bitmap);
554+
WARN_ON(!ocfs2_test_bit_unaligned(bit, dchunk->dqc_bitmap));
555+
ocfs2_clear_bit_unaligned(bit, dchunk->dqc_bitmap);
556556
le32_add_cpu(&dchunk->dqc_free, 1);
557557
unlock_buffer(qbh);
558558
ocfs2_journal_dirty(handle, qbh);
@@ -949,7 +949,7 @@ static struct ocfs2_quota_chunk *ocfs2_find_free_entry(struct super_block *sb,
949949
* ol_quota_entries_per_block(sb);
950950
}
951951

952-
found = ocfs2_find_next_zero_bit(dchunk->dqc_bitmap, len, 0);
952+
found = ocfs2_find_next_zero_bit_unaligned(dchunk->dqc_bitmap, len, 0);
953953
/* We failed? */
954954
if (found == len) {
955955
mlog(ML_ERROR, "Did not find empty entry in chunk %d with %u"
@@ -1213,7 +1213,7 @@ static void olq_alloc_dquot(struct buffer_head *bh, void *private)
12131213
struct ocfs2_local_disk_chunk *dchunk;
12141214

12151215
dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
1216-
ocfs2_set_bit(*offset, dchunk->dqc_bitmap);
1216+
ocfs2_set_bit_unaligned(*offset, dchunk->dqc_bitmap);
12171217
le32_add_cpu(&dchunk->dqc_free, -1);
12181218
}
12191219

@@ -1294,7 +1294,7 @@ int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
12941294
(od->dq_chunk->qc_headerbh->b_data);
12951295
/* Mark structure as freed */
12961296
lock_buffer(od->dq_chunk->qc_headerbh);
1297-
ocfs2_clear_bit(offset, dchunk->dqc_bitmap);
1297+
ocfs2_clear_bit_unaligned(offset, dchunk->dqc_bitmap);
12981298
le32_add_cpu(&dchunk->dqc_free, 1);
12991299
unlock_buffer(od->dq_chunk->qc_headerbh);
13001300
ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);

0 commit comments

Comments
 (0)