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; |
