diff options
author | Roland Dreier <rolandd@cisco.com> | 2007-10-09 22:59:15 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-10-09 22:59:15 -0400 |
commit | a394f83bdfec10b09d8cb111e622556b2e6fd0de (patch) | |
tree | bc9735ed3ccda810634173f01528741cefc71a6c /include/rdma | |
parent | 2be8e3ee8efd6f99ce454115c29d09750915021a (diff) |
IB/umad: Fix bit ordering and 32-on-64 problems on big endian systems
The declaration of struct ib_user_mad_reg_req.method_mask[] exported
to userspace was an array of __u32, but the kernel internally treated
it as a bitmap made up of longs. This makes a difference for 64-bit
big-endian kernels, where numbering the bits in an array of__u32 gives:
|31.....0|63....31|95....64|127...96|
while numbering the bits in an array of longs gives:
|63..............0|127............64|
64-bit userspace can handle this by just treating method_mask[] as an
array of longs, but 32-bit userspace is really stuck: the meaning of
the bits in method_mask[] depends on whether the kernel is 32-bit or
64-bit, and there's no sane way for userspace to know that.
Fix this by updating <rdma/ib_user_mad.h> to make it clear that
method_mask[] is an array of longs, and using a compat_ioctl method to
convert to an array of 64-bit longs to handle the 32-on-64 problem.
This fixes the interface description to match existing behavior (so
working binaries continue to work) in almost all situations, and gives
consistent semantics in the case of 32-bit userspace that can run on
either a 32-bit or 64-bit kernel, so that the same binary can work for
both 32-on-32 and 32-on-64 systems.
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'include/rdma')
-rw-r--r-- | include/rdma/ib_user_mad.h | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h index 2a32043d1abd..29d2c7205a90 100644 --- a/include/rdma/ib_user_mad.h +++ b/include/rdma/ib_user_mad.h | |||
@@ -147,6 +147,26 @@ struct ib_user_mad { | |||
147 | __u64 data[0]; | 147 | __u64 data[0]; |
148 | }; | 148 | }; |
149 | 149 | ||
150 | /* | ||
151 | * Earlier versions of this interface definition declared the | ||
152 | * method_mask[] member as an array of __u32 but treated it as a | ||
153 | * bitmap made up of longs in the kernel. This ambiguity meant that | ||
154 | * 32-bit big-endian applications that can run on both 32-bit and | ||
155 | * 64-bit kernels had no consistent ABI to rely on, and 64-bit | ||
156 | * big-endian applications that treated method_mask as being made up | ||
157 | * of 32-bit words would have their bitmap misinterpreted. | ||
158 | * | ||
159 | * To clear up this confusion, we change the declaration of | ||
160 | * method_mask[] to use unsigned long and handle the conversion from | ||
161 | * 32-bit userspace to 64-bit kernel for big-endian systems in the | ||
162 | * compat_ioctl method. Unfortunately, to keep the structure layout | ||
163 | * the same, we need the method_mask[] array to be aligned only to 4 | ||
164 | * bytes even when long is 64 bits, which forces us into this ugly | ||
165 | * typedef. | ||
166 | */ | ||
167 | typedef unsigned long __attribute__((aligned(4))) packed_ulong; | ||
168 | #define IB_USER_MAD_LONGS_PER_METHOD_MASK (128 / (8 * sizeof (long))) | ||
169 | |||
150 | /** | 170 | /** |
151 | * ib_user_mad_reg_req - MAD registration request | 171 | * ib_user_mad_reg_req - MAD registration request |
152 | * @id - Set by the kernel; used to identify agent in future requests. | 172 | * @id - Set by the kernel; used to identify agent in future requests. |
@@ -165,7 +185,7 @@ struct ib_user_mad { | |||
165 | */ | 185 | */ |
166 | struct ib_user_mad_reg_req { | 186 | struct ib_user_mad_reg_req { |
167 | __u32 id; | 187 | __u32 id; |
168 | __u32 method_mask[4]; | 188 | packed_ulong method_mask[IB_USER_MAD_LONGS_PER_METHOD_MASK]; |
169 | __u8 qpn; | 189 | __u8 qpn; |
170 | __u8 mgmt_class; | 190 | __u8 mgmt_class; |
171 | __u8 mgmt_class_version; | 191 | __u8 mgmt_class_version; |