From e08fb10148bfab6b4606f701733decf30aef8a44 Mon Sep 17 00:00:00 2001 From: yury Date: Thu, 26 Jun 2008 21:04:45 +0000 Subject: [PATCH] b=13934 r=tappro,fanyong - fixes unaligned access on 64 bit platforms. Thanks to Nikita for these patches. --- lustre/include/lustre/lustre_idl.h | 7 +++---- lustre/liblustre/dir.c | 21 +++++++++++++++++---- lustre/mdd/mdd_object.c | 6 +++--- lustre/osd/osd_internal.h | 4 ++++ lustre/utils/create_iam.c | 21 +++++++++++++++++---- lustre/utils/libiam.c | 20 ++++++++++++++++---- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/lustre/include/lustre/lustre_idl.h b/lustre/include/lustre/lustre_idl.h index 977ddcd..0c626dd 100644 --- a/lustre/include/lustre/lustre_idl.h +++ b/lustre/include/lustre/lustre_idl.h @@ -373,8 +373,7 @@ struct lu_dirent { struct lu_dirpage { __u64 ldp_hash_start; __u64 ldp_hash_end; - __u16 ldp_flags; - __u16 ldp_pad; + __u32 ldp_flags; __u32 ldp_pad0; struct lu_dirent ldp_entries[0]; }; @@ -385,7 +384,7 @@ enum lu_dirpage_flags { static inline struct lu_dirent *lu_dirent_start(struct lu_dirpage *dp) { - if (le16_to_cpu(dp->ldp_flags) & LDF_EMPTY) + if (le32_to_cpu(dp->ldp_flags) & LDF_EMPTY) return NULL; else return dp->ldp_entries; @@ -407,7 +406,7 @@ static inline int lu_dirent_size(struct lu_dirent *ent) { if (le16_to_cpu(ent->lde_reclen) == 0) { return (sizeof(*ent) + - le16_to_cpu(ent->lde_namelen) + 3) & ~3; + le16_to_cpu(ent->lde_namelen) + 7) & ~7; } return le16_to_cpu(ent->lde_reclen); } diff --git a/lustre/liblustre/dir.c b/lustre/liblustre/dir.c index ced5d95..16b75b6 100644 --- a/lustre/liblustre/dir.c +++ b/lustre/liblustre/dir.c @@ -164,6 +164,9 @@ static unsigned char ext2_filetype_table[EXT2_FT_MAX] = { [EXT2_FT_SYMLINK] DT_LNK, }; + +void (*memmover)(void *, const void *, size_t) = memmove; + #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP64(x) (((x)+sizeof(__u64)-1) & ~(sizeof(__u64)-1)) static int filldir(char *buf, int buflen, @@ -171,20 +174,30 @@ static int filldir(char *buf, int buflen, ino_t ino, unsigned int d_type, int *filled) { cfs_dirent_t *dirent = (cfs_dirent_t *) (buf + *filled); + cfs_dirent_t holder; int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namelen + 1); + /* + * @buf is not guaranteed to be properly aligned. To work around, + * first fill stack-allocated @holder, then copy @holder into @buf by + * memmove(). + */ + /* check overflow */ if ((*filled + reclen) > buflen) return 1; - dirent->d_ino = ino; + holder.d_ino = ino; #ifdef _DIRENT_HAVE_D_OFF - dirent->d_off = offset; + holder.d_off = offset; #endif - dirent->d_reclen = reclen; + holder.d_reclen = reclen; #ifdef _DIRENT_HAVE_D_TYPE - dirent->d_type = (unsigned short) d_type; + holder.d_type = (unsigned short) d_type; #endif + /* gcc unrolls memcpy() of structs into field-wise assignments, + * assuming proper alignment. Humor it. */ + (*memmover)(dirent, &holder, NAME_OFFSET(dirent)); memcpy(dirent->d_name, name, namelen); dirent->d_name[namelen] = 0; diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index 5e00c1c..a177f05 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -1348,7 +1348,7 @@ static int mdd_dir_page_build(const struct lu_env *env, int first, if (result != 0) break; - recsize = (sizeof(*ent) + len + 3) & ~3; + recsize = (sizeof(*ent) + len + 7) & ~7; hash = iops->store(env, it); *end = hash; @@ -1465,7 +1465,7 @@ static int __mdd_readpage(const struct lu_env *env, struct mdd_object *obj, * No pages were processed, mark this. */ dp->ldp_flags |= LDF_EMPTY; - dp->ldp_flags = cpu_to_le16(dp->ldp_flags); + dp->ldp_flags = cpu_to_le32(dp->ldp_flags); cfs_kunmap(rdpg->rp_pages[0]); } iops->put(env, it); @@ -1509,7 +1509,7 @@ static int mdd_readpage(const struct lu_env *env, struct md_object *obj, dp->ldp_hash_start = rdpg->rp_hash; dp->ldp_hash_end = DIR_END_OFF; dp->ldp_flags |= LDF_EMPTY; - dp->ldp_flags = cpu_to_le16(dp->ldp_flags); + dp->ldp_flags = cpu_to_le32(dp->ldp_flags); cfs_kunmap(pg); GOTO(out_unlock, rc = 0); } diff --git a/lustre/osd/osd_internal.h b/lustre/osd/osd_internal.h index 8a147ed..dc6dddc 100644 --- a/lustre/osd/osd_internal.h +++ b/lustre/osd/osd_internal.h @@ -121,7 +121,11 @@ struct osd_thread_info { struct lu_fid_pack oti_pack; + /* union to guarantee that ->oti_ipd[] has proper alignment. */ + union { char oti_ipd[DX_IPD_MAX_SIZE]; + long long oti_alignment_lieutenant; + }; #if OSD_COUNTERS int oti_r_locks; int oti_w_locks; diff --git a/lustre/utils/create_iam.c b/lustre/utils/create_iam.c index 5268802..914b0b4 100644 --- a/lustre/utils/create_iam.c +++ b/lustre/utils/create_iam.c @@ -103,6 +103,19 @@ enum { LVAR_ROUND = LVAR_PAD - 1 }; +/** + * Stores \a val at \a dst, where the latter is possibly unaligned. Uses + * memcpy(). This macro is needed to avoid dependency of user level tools on + * the kernel headers. + */ +#define STORE_UNALIGNED(val, dst) \ +({ \ + typeof(val) __val = (val); \ + \ + CLASSERT(sizeof(val) == sizeof(*(dst))); \ + memcpy(dst, &__val, sizeof(*(dst))); \ +}) + static void lfix_root(void *buf, int blocksize, int keysize, int ptrsize, int recsize) { @@ -144,9 +157,9 @@ static void lfix_root(void *buf, entry += keysize; /* now @entry points to */ if (ptrsize == 4) - *(u_int32_t *)entry = cpu_to_le32(1); + STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry); else - *(u_int64_t *)entry = cpu_to_le64(1); + STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry); } static void lfix_leaf(void *buf, @@ -208,9 +221,9 @@ static void lvar_root(void *buf, entry += sizeof(lvar_hash_t); /* now @entry points to */ if (ptrsize == 4) - *(u_int32_t *)entry = cpu_to_le32(1); + STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry); else - *(u_int64_t *)entry = cpu_to_le64(1); + STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry); } static int lvar_esize(int namelen, int recsize) diff --git a/lustre/utils/libiam.c b/lustre/utils/libiam.c index 36a7765..dafee2f 100644 --- a/lustre/utils/libiam.c +++ b/lustre/utils/libiam.c @@ -101,6 +101,18 @@ enum { LVAR_ROUND = LVAR_PAD - 1 }; +/** + * Stores \a val at \a dst, where the latter is possibly unaligned. Uses + * memcpy(). This macro is needed to avoid dependency of user level tools on + * the kernel headers. + */ +#define STORE_UNALIGNED(val, dst) \ +({ \ + typeof(*(dst)) __val = (val); \ + \ + memcpy(dst, &__val, sizeof *(dst)); \ +}) + static int root_limit(int rootgap, int blocksize, int size) { int limit; @@ -159,9 +171,9 @@ static void lfix_root(void *buf, entry += keysize; /* now @entry points to */ if (ptrsize == 4) - *(u_int32_t *)entry = cpu_to_le32(1); + STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry); else - *(u_int64_t *)entry = cpu_to_le64(1); + STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry); } static void lfix_leaf(void *buf, @@ -228,9 +240,9 @@ static void lvar_root(void *buf, entry += sizeof(lvar_hash_t); /* now @entry points to */ if (ptrsize == 4) - *(u_int32_t *)entry = cpu_to_le32(1); + STORE_UNALIGNED(cpu_to_le32(1), (u_int32_t *)entry); else - *(u_int64_t *)entry = cpu_to_le64(1); + STORE_UNALIGNED(cpu_to_le64(1), (u_int64_t *)entry); } static int lvar_esize(int namelen, int recsize) -- 1.8.3.1