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 | |
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')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl.c | 2 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl32.c | 224 | ||||
-rw-r--r-- | fs/xfs/xfs_itable.c | 42 | ||||
-rw-r--r-- | fs/xfs/xfs_itable.h | 20 |
4 files changed, 255 insertions, 33 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: |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index e725ddd3de5f..4c2454bcc714 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
@@ -202,6 +202,16 @@ xfs_bulkstat_one_dinode( | |||
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | STATIC int | ||
206 | xfs_bulkstat_one_fmt( | ||
207 | void __user *ubuffer, | ||
208 | const xfs_bstat_t *buffer) | ||
209 | { | ||
210 | if (copy_to_user(ubuffer, buffer, sizeof(*buffer))) | ||
211 | return -EFAULT; | ||
212 | return sizeof(*buffer); | ||
213 | } | ||
214 | |||
205 | /* | 215 | /* |
206 | * Return stat information for one inode. | 216 | * Return stat information for one inode. |
207 | * Return 0 if ok, else errno. | 217 | * Return 0 if ok, else errno. |
@@ -221,6 +231,7 @@ xfs_bulkstat_one( | |||
221 | xfs_bstat_t *buf; /* return buffer */ | 231 | xfs_bstat_t *buf; /* return buffer */ |
222 | int error = 0; /* error value */ | 232 | int error = 0; /* error value */ |
223 | xfs_dinode_t *dip; /* dinode inode pointer */ | 233 | xfs_dinode_t *dip; /* dinode inode pointer */ |
234 | bulkstat_one_fmt_pf formatter = private_data ? : xfs_bulkstat_one_fmt; | ||
224 | 235 | ||
225 | dip = (xfs_dinode_t *)dibuff; | 236 | dip = (xfs_dinode_t *)dibuff; |
226 | *stat = BULKSTAT_RV_NOTHING; | 237 | *stat = BULKSTAT_RV_NOTHING; |
@@ -243,14 +254,15 @@ xfs_bulkstat_one( | |||
243 | xfs_bulkstat_one_dinode(mp, ino, dip, buf); | 254 | xfs_bulkstat_one_dinode(mp, ino, dip, buf); |
244 | } | 255 | } |
245 | 256 | ||
246 | if (copy_to_user(buffer, buf, sizeof(*buf))) { | 257 | error = formatter(buffer, buf); |
258 | if (error < 0) { | ||
247 | error = EFAULT; | 259 | error = EFAULT; |
248 | goto out_free; | 260 | goto out_free; |
249 | } | 261 | } |
250 | 262 | ||
251 | *stat = BULKSTAT_RV_DIDONE; | 263 | *stat = BULKSTAT_RV_DIDONE; |
252 | if (ubused) | 264 | if (ubused) |
253 | *ubused = sizeof(*buf); | 265 | *ubused = error; |
254 | 266 | ||
255 | out_free: | 267 | out_free: |
256 | kmem_free(buf, sizeof(*buf)); | 268 | kmem_free(buf, sizeof(*buf)); |
@@ -748,6 +760,19 @@ xfs_bulkstat_single( | |||
748 | return 0; | 760 | return 0; |
749 | } | 761 | } |
750 | 762 | ||
763 | int | ||
764 | xfs_inumbers_fmt( | ||
765 | void __user *ubuffer, /* buffer to write to */ | ||
766 | const xfs_inogrp_t *buffer, /* buffer to read from */ | ||
767 | long count, /* # of elements to read */ | ||
768 | long *written) /* # of bytes written */ | ||
769 | { | ||
770 | if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer))) | ||
771 | return -EFAULT; | ||
772 | *written = count * sizeof(*buffer); | ||
773 | return 0; | ||
774 | } | ||
775 | |||
751 | /* | 776 | /* |
752 | * Return inode number table for the filesystem. | 777 | * Return inode number table for the filesystem. |
753 | */ | 778 | */ |
@@ -756,7 +781,8 @@ xfs_inumbers( | |||
756 | xfs_mount_t *mp, /* mount point for filesystem */ | 781 | xfs_mount_t *mp, /* mount point for filesystem */ |
757 | xfs_ino_t *lastino, /* last inode returned */ | 782 | xfs_ino_t *lastino, /* last inode returned */ |
758 | int *count, /* size of buffer/count returned */ | 783 | int *count, /* size of buffer/count returned */ |
759 | xfs_inogrp_t __user *ubuffer)/* buffer with inode descriptions */ | 784 | void __user *ubuffer,/* buffer with inode descriptions */ |
785 | inumbers_fmt_pf formatter) | ||
760 | { | 786 | { |
761 | xfs_buf_t *agbp; | 787 | xfs_buf_t *agbp; |
762 | xfs_agino_t agino; | 788 | xfs_agino_t agino; |
@@ -835,12 +861,12 @@ xfs_inumbers( | |||
835 | bufidx++; | 861 | bufidx++; |
836 | left--; | 862 | left--; |
837 | if (bufidx == bcount) { | 863 | if (bufidx == bcount) { |
838 | if (copy_to_user(ubuffer, buffer, | 864 | long written; |
839 | bufidx * sizeof(*buffer))) { | 865 | if (formatter(ubuffer, buffer, bufidx, &written)) { |
840 | error = XFS_ERROR(EFAULT); | 866 | error = XFS_ERROR(EFAULT); |
841 | break; | 867 | break; |
842 | } | 868 | } |
843 | ubuffer += bufidx; | 869 | ubuffer += written; |
844 | *count += bufidx; | 870 | *count += bufidx; |
845 | bufidx = 0; | 871 | bufidx = 0; |
846 | } | 872 | } |
@@ -862,8 +888,8 @@ xfs_inumbers( | |||
862 | } | 888 | } |
863 | if (!error) { | 889 | if (!error) { |
864 | if (bufidx) { | 890 | if (bufidx) { |
865 | if (copy_to_user(ubuffer, buffer, | 891 | long written; |
866 | bufidx * sizeof(*buffer))) | 892 | if (formatter(ubuffer, buffer, bufidx, &written)) |
867 | error = XFS_ERROR(EFAULT); | 893 | error = XFS_ERROR(EFAULT); |
868 | else | 894 | else |
869 | *count += bufidx; | 895 | *count += bufidx; |
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h index f25a28862a17..a1f18fce9b70 100644 --- a/fs/xfs/xfs_itable.h +++ b/fs/xfs/xfs_itable.h | |||
@@ -69,6 +69,10 @@ xfs_bulkstat_single( | |||
69 | char __user *buffer, | 69 | char __user *buffer, |
70 | int *done); | 70 | int *done); |
71 | 71 | ||
72 | typedef int (*bulkstat_one_fmt_pf)( /* used size in bytes or negative error */ | ||
73 | void __user *ubuffer, /* buffer to write to */ | ||
74 | const xfs_bstat_t *buffer); /* buffer to read from */ | ||
75 | |||
72 | int | 76 | int |
73 | xfs_bulkstat_one( | 77 | xfs_bulkstat_one( |
74 | xfs_mount_t *mp, | 78 | xfs_mount_t *mp, |
@@ -86,11 +90,25 @@ xfs_internal_inum( | |||
86 | xfs_mount_t *mp, | 90 | xfs_mount_t *mp, |
87 | xfs_ino_t ino); | 91 | xfs_ino_t ino); |
88 | 92 | ||
93 | typedef int (*inumbers_fmt_pf)( | ||
94 | void __user *ubuffer, /* buffer to write to */ | ||
95 | const xfs_inogrp_t *buffer, /* buffer to read from */ | ||
96 | long count, /* # of elements to read */ | ||
97 | long *written); /* # of bytes written */ | ||
98 | |||
99 | int | ||
100 | xfs_inumbers_fmt( | ||
101 | void __user *ubuffer, /* buffer to write to */ | ||
102 | const xfs_inogrp_t *buffer, /* buffer to read from */ | ||
103 | long count, /* # of elements to read */ | ||
104 | long *written); /* # of bytes written */ | ||
105 | |||
89 | int /* error status */ | 106 | int /* error status */ |
90 | xfs_inumbers( | 107 | xfs_inumbers( |
91 | xfs_mount_t *mp, /* mount point for filesystem */ | 108 | xfs_mount_t *mp, /* mount point for filesystem */ |
92 | xfs_ino_t *last, /* last inode returned */ | 109 | xfs_ino_t *last, /* last inode returned */ |
93 | int *count, /* size of buffer/count returned */ | 110 | int *count, /* size of buffer/count returned */ |
94 | xfs_inogrp_t __user *buffer);/* buffer with inode info */ | 111 | void __user *buffer, /* buffer with inode info */ |
112 | inumbers_fmt_pf formatter); | ||
95 | 113 | ||
96 | #endif /* __XFS_ITABLE_H__ */ | 114 | #endif /* __XFS_ITABLE_H__ */ |