diff options
author | Michal Marek <mmarek@suse.cz> | 2007-07-10 21:10:19 -0400 |
---|---|---|
committer | Tim Shimmin <tes@chook.melbourne.sgi.com> | 2007-07-14 01:42:50 -0400 |
commit | faa63e9584df41020440756b8b90b7b63f95e4f6 (patch) | |
tree | 9b0369a028d682e36ab91396bcebb1ecfb298e29 /fs/xfs/linux-2.6 | |
parent | 1fa503df66f7bffc0ff62662626897eec79446c2 (diff) |
[XFS] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} & XFS_IOC_FSINUMBERS in compat mode
* 32bit struct xfs_fsop_bulkreq has different size and layout of
members, no matter the alignment. Move the code out of the #else
branch (why was it there in the first place?). Define _32 variants of
the ioctl constants.
* 32bit struct xfs_bstat is different because of time_t and on
i386 because of different padding. Make xfs_bulkstat_one() accept a
custom "output formatter" in the private_data argument which takes care
of the xfs_bulkstat_one_compat() that takes care of the different
layout in the compat case.
* i386 struct xfs_inogrp has different padding.
Add a similar "output formatter" mecanism to xfs_inumbers().
SGI-PV: 967354
SGI-Modid: xfs-linux-melb:xfs-kern:29102a
Signed-off-by: Michal Marek <mmarek@suse.cz>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
Diffstat (limited to 'fs/xfs/linux-2.6')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl.c | 2 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl32.c | 224 |
2 files changed, 202 insertions, 24 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index ff5c41ff8d40..5917808abbd6 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c | |||
@@ -1019,7 +1019,7 @@ xfs_ioc_bulkstat( | |||
1019 | 1019 | ||
1020 | if (cmd == XFS_IOC_FSINUMBERS) | 1020 | if (cmd == XFS_IOC_FSINUMBERS) |
1021 | error = xfs_inumbers(mp, &inlast, &count, | 1021 | error = xfs_inumbers(mp, &inlast, &count, |
1022 | bulkreq.ubuffer); | 1022 | bulkreq.ubuffer, xfs_inumbers_fmt); |
1023 | else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) | 1023 | else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) |
1024 | error = xfs_bulkstat_single(mp, &inlast, | 1024 | error = xfs_bulkstat_single(mp, &inlast, |
1025 | bulkreq.ubuffer, &done); | 1025 | bulkreq.ubuffer, &done); |
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 87163fb9746b..141cf15067c2 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c | |||
@@ -23,10 +23,25 @@ | |||
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
25 | #include "xfs.h" | 25 | #include "xfs.h" |
26 | #include "xfs_types.h" | ||
27 | #include "xfs_fs.h" | 26 | #include "xfs_fs.h" |
27 | #include "xfs_bit.h" | ||
28 | #include "xfs_log.h" | ||
29 | #include "xfs_inum.h" | ||
30 | #include "xfs_trans.h" | ||
31 | #include "xfs_sb.h" | ||
32 | #include "xfs_ag.h" | ||
33 | #include "xfs_dir2.h" | ||
34 | #include "xfs_dmapi.h" | ||
35 | #include "xfs_mount.h" | ||
36 | #include "xfs_bmap_btree.h" | ||
37 | #include "xfs_attr_sf.h" | ||
38 | #include "xfs_dir2_sf.h" | ||
28 | #include "xfs_vfs.h" | 39 | #include "xfs_vfs.h" |
29 | #include "xfs_vnode.h" | 40 | #include "xfs_vnode.h" |
41 | #include "xfs_dinode.h" | ||
42 | #include "xfs_inode.h" | ||
43 | #include "xfs_itable.h" | ||
44 | #include "xfs_error.h" | ||
30 | #include "xfs_dfrag.h" | 45 | #include "xfs_dfrag.h" |
31 | 46 | ||
32 | #define _NATIVE_IOC(cmd, type) \ | 47 | #define _NATIVE_IOC(cmd, type) \ |
@@ -34,6 +49,7 @@ | |||
34 | 49 | ||
35 | #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) | 50 | #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) |
36 | #define BROKEN_X86_ALIGNMENT | 51 | #define BROKEN_X86_ALIGNMENT |
52 | #define _PACKED __attribute__((packed)) | ||
37 | /* on ia32 l_start is on a 32-bit boundary */ | 53 | /* on ia32 l_start is on a 32-bit boundary */ |
38 | typedef struct xfs_flock64_32 { | 54 | typedef struct xfs_flock64_32 { |
39 | __s16 l_type; | 55 | __s16 l_type; |
@@ -111,35 +127,196 @@ STATIC unsigned long xfs_ioctl32_geom_v1(unsigned long arg) | |||
111 | return (unsigned long)p; | 127 | return (unsigned long)p; |
112 | } | 128 | } |
113 | 129 | ||
130 | typedef struct compat_xfs_inogrp { | ||
131 | __u64 xi_startino; /* starting inode number */ | ||
132 | __s32 xi_alloccount; /* # bits set in allocmask */ | ||
133 | __u64 xi_allocmask; /* mask of allocated inodes */ | ||
134 | } __attribute__((packed)) compat_xfs_inogrp_t; | ||
135 | |||
136 | STATIC int xfs_inumbers_fmt_compat( | ||
137 | void __user *ubuffer, | ||
138 | const xfs_inogrp_t *buffer, | ||
139 | long count, | ||
140 | long *written) | ||
141 | { | ||
142 | compat_xfs_inogrp_t *p32 = ubuffer; | ||
143 | long i; | ||
144 | |||
145 | for (i = 0; i < count; i++) { | ||
146 | if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) || | ||
147 | put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) || | ||
148 | put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask)) | ||
149 | return -EFAULT; | ||
150 | } | ||
151 | *written = count * sizeof(*p32); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
114 | #else | 155 | #else |
115 | 156 | ||
116 | typedef struct xfs_fsop_bulkreq32 { | 157 | #define xfs_inumbers_fmt_compat xfs_inumbers_fmt |
158 | #define _PACKED | ||
159 | |||
160 | #endif | ||
161 | |||
162 | /* XFS_IOC_FSBULKSTAT and friends */ | ||
163 | |||
164 | typedef struct compat_xfs_bstime { | ||
165 | __s32 tv_sec; /* seconds */ | ||
166 | __s32 tv_nsec; /* and nanoseconds */ | ||
167 | } compat_xfs_bstime_t; | ||
168 | |||
169 | STATIC int xfs_bstime_store_compat( | ||
170 | compat_xfs_bstime_t __user *p32, | ||
171 | const xfs_bstime_t *p) | ||
172 | { | ||
173 | __s32 sec32; | ||
174 | |||
175 | sec32 = p->tv_sec; | ||
176 | if (put_user(sec32, &p32->tv_sec) || | ||
177 | put_user(p->tv_nsec, &p32->tv_nsec)) | ||
178 | return -EFAULT; | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | typedef struct compat_xfs_bstat { | ||
183 | __u64 bs_ino; /* inode number */ | ||
184 | __u16 bs_mode; /* type and mode */ | ||
185 | __u16 bs_nlink; /* number of links */ | ||
186 | __u32 bs_uid; /* user id */ | ||
187 | __u32 bs_gid; /* group id */ | ||
188 | __u32 bs_rdev; /* device value */ | ||
189 | __s32 bs_blksize; /* block size */ | ||
190 | __s64 bs_size; /* file size */ | ||
191 | compat_xfs_bstime_t bs_atime; /* access time */ | ||
192 | compat_xfs_bstime_t bs_mtime; /* modify time */ | ||
193 | compat_xfs_bstime_t bs_ctime; /* inode change time */ | ||
194 | int64_t bs_blocks; /* number of blocks */ | ||
195 | __u32 bs_xflags; /* extended flags */ | ||
196 | __s32 bs_extsize; /* extent size */ | ||
197 | __s32 bs_extents; /* number of extents */ | ||
198 | __u32 bs_gen; /* generation count */ | ||
199 | __u16 bs_projid; /* project id */ | ||
200 | unsigned char bs_pad[14]; /* pad space, unused */ | ||
201 | __u32 bs_dmevmask; /* DMIG event mask */ | ||
202 | __u16 bs_dmstate; /* DMIG state info */ | ||
203 | __u16 bs_aextents; /* attribute number of extents */ | ||
204 | } _PACKED compat_xfs_bstat_t; | ||
205 | |||
206 | STATIC int xfs_bulkstat_one_fmt_compat( | ||
207 | void __user *ubuffer, | ||
208 | const xfs_bstat_t *buffer) | ||
209 | { | ||
210 | compat_xfs_bstat_t __user *p32 = ubuffer; | ||
211 | |||
212 | if (put_user(buffer->bs_ino, &p32->bs_ino) || | ||
213 | put_user(buffer->bs_mode, &p32->bs_mode) || | ||
214 | put_user(buffer->bs_nlink, &p32->bs_nlink) || | ||
215 | put_user(buffer->bs_uid, &p32->bs_uid) || | ||
216 | put_user(buffer->bs_gid, &p32->bs_gid) || | ||
217 | put_user(buffer->bs_rdev, &p32->bs_rdev) || | ||
218 | put_user(buffer->bs_blksize, &p32->bs_blksize) || | ||
219 | put_user(buffer->bs_size, &p32->bs_size) || | ||
220 | xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) || | ||
221 | xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) || | ||
222 | xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) || | ||
223 | put_user(buffer->bs_blocks, &p32->bs_blocks) || | ||
224 | put_user(buffer->bs_xflags, &p32->bs_xflags) || | ||
225 | put_user(buffer->bs_extsize, &p32->bs_extsize) || | ||
226 | put_user(buffer->bs_extents, &p32->bs_extents) || | ||
227 | put_user(buffer->bs_gen, &p32->bs_gen) || | ||
228 | put_user(buffer->bs_projid, &p32->bs_projid) || | ||
229 | put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) || | ||
230 | put_user(buffer->bs_dmstate, &p32->bs_dmstate) || | ||
231 | put_user(buffer->bs_aextents, &p32->bs_aextents)) | ||
232 | return -EFAULT; | ||
233 | return sizeof(*p32); | ||
234 | } | ||
235 | |||
236 | |||
237 | |||
238 | typedef struct compat_xfs_fsop_bulkreq { | ||
117 | compat_uptr_t lastip; /* last inode # pointer */ | 239 | compat_uptr_t lastip; /* last inode # pointer */ |
118 | __s32 icount; /* count of entries in buffer */ | 240 | __s32 icount; /* count of entries in buffer */ |
119 | compat_uptr_t ubuffer; /* user buffer for inode desc. */ | 241 | compat_uptr_t ubuffer; /* user buffer for inode desc. */ |
120 | __s32 ocount; /* output count pointer */ | 242 | compat_uptr_t ocount; /* output count pointer */ |
121 | } xfs_fsop_bulkreq32_t; | 243 | } compat_xfs_fsop_bulkreq_t; |
122 | 244 | ||
123 | STATIC unsigned long | 245 | #define XFS_IOC_FSBULKSTAT_32 \ |
124 | xfs_ioctl32_bulkstat( | 246 | _IOWR('X', 101, struct compat_xfs_fsop_bulkreq) |
125 | unsigned long arg) | 247 | #define XFS_IOC_FSBULKSTAT_SINGLE_32 \ |
248 | _IOWR('X', 102, struct compat_xfs_fsop_bulkreq) | ||
249 | #define XFS_IOC_FSINUMBERS_32 \ | ||
250 | _IOWR('X', 103, struct compat_xfs_fsop_bulkreq) | ||
251 | |||
252 | /* copied from xfs_ioctl.c */ | ||
253 | STATIC int | ||
254 | xfs_ioc_bulkstat_compat( | ||
255 | xfs_mount_t *mp, | ||
256 | unsigned int cmd, | ||
257 | void __user *arg) | ||
126 | { | 258 | { |
127 | xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg; | 259 | compat_xfs_fsop_bulkreq_t __user *p32 = (void __user *)arg; |
128 | xfs_fsop_bulkreq_t __user *p = compat_alloc_user_space(sizeof(*p)); | ||
129 | u32 addr; | 260 | u32 addr; |
261 | xfs_fsop_bulkreq_t bulkreq; | ||
262 | int count; /* # of records returned */ | ||
263 | xfs_ino_t inlast; /* last inode number */ | ||
264 | int done; | ||
265 | int error; | ||
266 | |||
267 | /* done = 1 if there are more stats to get and if bulkstat */ | ||
268 | /* should be called again (unused here, but used in dmapi) */ | ||
130 | 269 | ||
131 | if (get_user(addr, &p32->lastip) || | 270 | if (!capable(CAP_SYS_ADMIN)) |
132 | put_user(compat_ptr(addr), &p->lastip) || | 271 | return -EPERM; |
133 | copy_in_user(&p->icount, &p32->icount, sizeof(s32)) || | 272 | |
134 | get_user(addr, &p32->ubuffer) || | 273 | if (XFS_FORCED_SHUTDOWN(mp)) |
135 | put_user(compat_ptr(addr), &p->ubuffer) || | 274 | return -XFS_ERROR(EIO); |
136 | get_user(addr, &p32->ocount) || | 275 | |
137 | put_user(compat_ptr(addr), &p->ocount)) | 276 | if (get_user(addr, &p32->lastip)) |
277 | return -EFAULT; | ||
278 | bulkreq.lastip = compat_ptr(addr); | ||
279 | if (get_user(bulkreq.icount, &p32->icount) || | ||
280 | get_user(addr, &p32->ubuffer)) | ||
138 | return -EFAULT; | 281 | return -EFAULT; |
282 | bulkreq.ubuffer = compat_ptr(addr); | ||
283 | if (get_user(addr, &p32->ocount)) | ||
284 | return -EFAULT; | ||
285 | bulkreq.ocount = compat_ptr(addr); | ||
139 | 286 | ||
140 | return (unsigned long)p; | 287 | if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) |
288 | return -XFS_ERROR(EFAULT); | ||
289 | |||
290 | if ((count = bulkreq.icount) <= 0) | ||
291 | return -XFS_ERROR(EINVAL); | ||
292 | |||
293 | if (cmd == XFS_IOC_FSINUMBERS) | ||
294 | error = xfs_inumbers(mp, &inlast, &count, | ||
295 | bulkreq.ubuffer, xfs_inumbers_fmt_compat); | ||
296 | else { | ||
297 | /* declare a var to get a warning in case the type changes */ | ||
298 | bulkstat_one_fmt_pf formatter = xfs_bulkstat_one_fmt_compat; | ||
299 | error = xfs_bulkstat(mp, &inlast, &count, | ||
300 | xfs_bulkstat_one, formatter, | ||
301 | sizeof(compat_xfs_bstat_t), bulkreq.ubuffer, | ||
302 | BULKSTAT_FG_QUICK, &done); | ||
303 | } | ||
304 | if (error) | ||
305 | return -error; | ||
306 | |||
307 | if (bulkreq.ocount != NULL) { | ||
308 | if (copy_to_user(bulkreq.lastip, &inlast, | ||
309 | sizeof(xfs_ino_t))) | ||
310 | return -XFS_ERROR(EFAULT); | ||
311 | |||
312 | if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) | ||
313 | return -XFS_ERROR(EFAULT); | ||
314 | } | ||
315 | |||
316 | return 0; | ||
141 | } | 317 | } |
142 | #endif | 318 | |
319 | |||
143 | 320 | ||
144 | typedef struct compat_xfs_fsop_handlereq { | 321 | typedef struct compat_xfs_fsop_handlereq { |
145 | __u32 fd; /* fd for FD_TO_HANDLE */ | 322 | __u32 fd; /* fd for FD_TO_HANDLE */ |
@@ -261,12 +438,13 @@ xfs_compat_ioctl( | |||
261 | case XFS_IOC_SWAPEXT: | 438 | case XFS_IOC_SWAPEXT: |
262 | break; | 439 | break; |
263 | 440 | ||
264 | case XFS_IOC_FSBULKSTAT_SINGLE: | ||
265 | case XFS_IOC_FSBULKSTAT: | ||
266 | case XFS_IOC_FSINUMBERS: | ||
267 | arg = xfs_ioctl32_bulkstat(arg); | ||
268 | break; | ||
269 | #endif | 441 | #endif |
442 | case XFS_IOC_FSBULKSTAT_32: | ||
443 | case XFS_IOC_FSBULKSTAT_SINGLE_32: | ||
444 | case XFS_IOC_FSINUMBERS_32: | ||
445 | cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq); | ||
446 | return xfs_ioc_bulkstat_compat(XFS_BHVTOI(VNHEAD(vp))->i_mount, | ||
447 | cmd, (void*)arg); | ||
270 | case XFS_IOC_FD_TO_HANDLE_32: | 448 | case XFS_IOC_FD_TO_HANDLE_32: |
271 | case XFS_IOC_PATH_TO_HANDLE_32: | 449 | case XFS_IOC_PATH_TO_HANDLE_32: |
272 | case XFS_IOC_PATH_TO_FSHANDLE_32: | 450 | case XFS_IOC_PATH_TO_FSHANDLE_32: |