aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@sandeen.net>2008-11-27 22:23:35 -0500
committerNiv Sardi <xaiki@sgi.com>2008-11-30 19:29:00 -0500
commit8a7141a8b931d60d42830432b82078cd6dace83b (patch)
treee5f1f2573b7e759e8d04b39757c1491689037485 /fs
parent0924b585fc49bf371bc700c23e516a538bf589af (diff)
[XFS] convert xfs_getbmap to take formatter functions
Preliminary work to hook up fiemap, this allows us to pass in an arbitrary formatter to copy extent data back to userspace. The formatter takes info for 1 extent, a pointer to the user "thing*" and a pointer to a "filled" variable to indicate whether a userspace buffer did get filled in (for fiemap, hole "extents" are skipped). I'm just using the getbmapx struct as a "common denominator" because as far as I can see, it holds all info that any formatters will care about. ("*thing" because fiemap doesn't pass the user pointer around, but rather has a pointer to a fiemap info structure, and helpers associated with it) Signed-off-by: Eric Sandeen <sandeen@sandeen.net> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Niv Sardi <xaiki@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c64
-rw-r--r--fs/xfs/xfs_bmap.c62
-rw-r--r--fs/xfs/xfs_bmap.h11
-rw-r--r--fs/xfs/xfs_fs.h12
4 files changed, 71 insertions, 78 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index f1bd6c36e6fe..d59705999534 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -1250,43 +1250,67 @@ xfs_ioc_setxflags(
1250} 1250}
1251 1251
1252STATIC int 1252STATIC int
1253xfs_getbmap_format(void **ap, struct getbmapx *bmv, int *full)
1254{
1255 struct getbmap __user *base = *ap;
1256
1257 /* copy only getbmap portion (not getbmapx) */
1258 if (copy_to_user(base, bmv, sizeof(struct getbmap)))
1259 return XFS_ERROR(EFAULT);
1260
1261 *ap += sizeof(struct getbmap);
1262 return 0;
1263}
1264
1265STATIC int
1253xfs_ioc_getbmap( 1266xfs_ioc_getbmap(
1254 struct xfs_inode *ip, 1267 struct xfs_inode *ip,
1255 int ioflags, 1268 int ioflags,
1256 unsigned int cmd, 1269 unsigned int cmd,
1257 void __user *arg) 1270 void __user *arg)
1258{ 1271{
1259 struct getbmap bm; 1272 struct getbmapx bmx;
1260 int iflags;
1261 int error; 1273 int error;
1262 1274
1263 if (copy_from_user(&bm, arg, sizeof(bm))) 1275 if (copy_from_user(&bmx, arg, sizeof(struct getbmapx)))
1264 return -XFS_ERROR(EFAULT); 1276 return -XFS_ERROR(EFAULT);
1265 1277
1266 if (bm.bmv_count < 2) 1278 if (bmx.bmv_count < 2)
1267 return -XFS_ERROR(EINVAL); 1279 return -XFS_ERROR(EINVAL);
1268 1280
1269 iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); 1281 bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
1270 if (ioflags & IO_INVIS) 1282 if (ioflags & IO_INVIS)
1271 iflags |= BMV_IF_NO_DMAPI_READ; 1283 bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;
1272 1284
1273 error = xfs_getbmap(ip, &bm, (struct getbmap __user *)arg+1, iflags); 1285 error = xfs_getbmap(ip, &bmx, xfs_getbmap_format,
1286 (struct getbmap *)arg+1);
1274 if (error) 1287 if (error)
1275 return -error; 1288 return -error;
1276 1289
1277 if (copy_to_user(arg, &bm, sizeof(bm))) 1290 /* copy back header - only size of getbmap */
1291 if (copy_to_user(arg, &bmx, sizeof(struct getbmap)))
1278 return -XFS_ERROR(EFAULT); 1292 return -XFS_ERROR(EFAULT);
1279 return 0; 1293 return 0;
1280} 1294}
1281 1295
1282STATIC int 1296STATIC int
1297xfs_getbmapx_format(void **ap, struct getbmapx *bmv, int *full)
1298{
1299 struct getbmapx __user *base = *ap;
1300
1301 if (copy_to_user(base, bmv, sizeof(struct getbmapx)))
1302 return XFS_ERROR(EFAULT);
1303
1304 *ap += sizeof(struct getbmapx);
1305 return 0;
1306}
1307
1308STATIC int
1283xfs_ioc_getbmapx( 1309xfs_ioc_getbmapx(
1284 struct xfs_inode *ip, 1310 struct xfs_inode *ip,
1285 void __user *arg) 1311 void __user *arg)
1286{ 1312{
1287 struct getbmapx bmx; 1313 struct getbmapx bmx;
1288 struct getbmap bm;
1289 int iflags;
1290 int error; 1314 int error;
1291 1315
1292 if (copy_from_user(&bmx, arg, sizeof(bmx))) 1316 if (copy_from_user(&bmx, arg, sizeof(bmx)))
@@ -1295,26 +1319,16 @@ xfs_ioc_getbmapx(
1295 if (bmx.bmv_count < 2) 1319 if (bmx.bmv_count < 2)
1296 return -XFS_ERROR(EINVAL); 1320 return -XFS_ERROR(EINVAL);
1297 1321
1298 /* 1322 if (bmx.bmv_iflags & (~BMV_IF_VALID))
1299 * Map input getbmapx structure to a getbmap
1300 * structure for xfs_getbmap.
1301 */
1302 GETBMAP_CONVERT(bmx, bm);
1303
1304 iflags = bmx.bmv_iflags;
1305
1306 if (iflags & (~BMV_IF_VALID))
1307 return -XFS_ERROR(EINVAL); 1323 return -XFS_ERROR(EINVAL);
1308 1324
1309 iflags |= BMV_IF_EXTENDED; 1325 error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format,
1310 1326 (struct getbmapx *)arg+1);
1311 error = xfs_getbmap(ip, &bm, (struct getbmapx __user *)arg+1, iflags);
1312 if (error) 1327 if (error)
1313 return -error; 1328 return -error;
1314 1329
1315 GETBMAP_CONVERT(bm, bmx); 1330 /* copy back header */
1316 1331 if (copy_to_user(arg, &bmx, sizeof(struct getbmapx)))
1317 if (copy_to_user(arg, &bmx, sizeof(bmx)))
1318 return -XFS_ERROR(EFAULT); 1332 return -XFS_ERROR(EFAULT);
1319 1333
1320 return 0; 1334 return 0;
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index c3912213645c..8077580a7199 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -5811,9 +5811,9 @@ error0:
5811STATIC int 5811STATIC int
5812xfs_getbmapx_fix_eof_hole( 5812xfs_getbmapx_fix_eof_hole(
5813 xfs_inode_t *ip, /* xfs incore inode pointer */ 5813 xfs_inode_t *ip, /* xfs incore inode pointer */
5814 struct getbmap *out, /* output structure */ 5814 struct getbmapx *out, /* output structure */
5815 int prealloced, /* this is a file with 5815 int prealloced, /* this is a file with
5816 * preallocated data space */ 5816 * preallocated data space */
5817 __int64_t end, /* last block requested */ 5817 __int64_t end, /* last block requested */
5818 xfs_fsblock_t startblock) 5818 xfs_fsblock_t startblock)
5819{ 5819{
@@ -5839,14 +5839,18 @@ xfs_getbmapx_fix_eof_hole(
5839} 5839}
5840 5840
5841/* 5841/*
5842 * Fcntl interface to xfs_bmapi. 5842 * Get inode's extents as described in bmv, and format for output.
5843 * Calls formatter to fill the user's buffer until all extents
5844 * are mapped, until the passed-in bmv->bmv_count slots have
5845 * been filled, or until the formatter short-circuits the loop,
5846 * if it is tracking filled-in extents on its own.
5843 */ 5847 */
5844int /* error code */ 5848int /* error code */
5845xfs_getbmap( 5849xfs_getbmap(
5846 xfs_inode_t *ip, 5850 xfs_inode_t *ip,
5847 struct getbmap *bmv, /* user bmap structure */ 5851 struct getbmapx *bmv, /* user bmap structure */
5848 void __user *ap, /* pointer to user's array */ 5852 xfs_bmap_format_t formatter, /* format to user */
5849 int interface) /* interface flags */ 5853 void *arg) /* formatter arg */
5850{ 5854{
5851 __int64_t bmvend; /* last block requested */ 5855 __int64_t bmvend; /* last block requested */
5852 int error; /* return value */ 5856 int error; /* return value */
@@ -5859,19 +5863,20 @@ xfs_getbmap(
5859 int nexleft; /* # of user extents left */ 5863 int nexleft; /* # of user extents left */
5860 int subnex; /* # of bmapi's can do */ 5864 int subnex; /* # of bmapi's can do */
5861 int nmap; /* number of map entries */ 5865 int nmap; /* number of map entries */
5862 struct getbmap out; /* output structure */ 5866 struct getbmapx out; /* output structure */
5863 int whichfork; /* data or attr fork */ 5867 int whichfork; /* data or attr fork */
5864 int prealloced; /* this is a file with 5868 int prealloced; /* this is a file with
5865 * preallocated data space */ 5869 * preallocated data space */
5866 int sh_unwritten; /* true, if unwritten */ 5870 int sh_unwritten; /* true, if unwritten */
5867 /* extents listed separately */ 5871 /* extents listed separately */
5872 int iflags; /* interface flags */
5868 int bmapi_flags; /* flags for xfs_bmapi */ 5873 int bmapi_flags; /* flags for xfs_bmapi */
5869 __int32_t oflags; /* getbmapx bmv_oflags field */
5870 5874
5871 mp = ip->i_mount; 5875 mp = ip->i_mount;
5876 iflags = bmv->bmv_iflags;
5872 5877
5873 whichfork = interface & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK; 5878 whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK;
5874 sh_unwritten = (interface & BMV_IF_PREALLOC) != 0; 5879 sh_unwritten = (iflags & BMV_IF_PREALLOC) != 0;
5875 5880
5876 /* If the BMV_IF_NO_DMAPI_READ interface bit specified, do not 5881 /* If the BMV_IF_NO_DMAPI_READ interface bit specified, do not
5877 * generate a DMAPI read event. Otherwise, if the DM_EVENT_READ 5882 * generate a DMAPI read event. Otherwise, if the DM_EVENT_READ
@@ -5886,7 +5891,7 @@ xfs_getbmap(
5886 * could misinterpret holes in a DMAPI file as true holes, 5891 * could misinterpret holes in a DMAPI file as true holes,
5887 * when in fact they may represent offline user data. 5892 * when in fact they may represent offline user data.
5888 */ 5893 */
5889 if ((interface & BMV_IF_NO_DMAPI_READ) == 0 && 5894 if ((iflags & BMV_IF_NO_DMAPI_READ) == 0 &&
5890 DM_EVENT_ENABLED(ip, DM_EVENT_READ) && 5895 DM_EVENT_ENABLED(ip, DM_EVENT_READ) &&
5891 whichfork == XFS_DATA_FORK) { 5896 whichfork == XFS_DATA_FORK) {
5892 error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL); 5897 error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL);
@@ -5993,52 +5998,35 @@ xfs_getbmap(
5993 ASSERT(nmap <= subnex); 5998 ASSERT(nmap <= subnex);
5994 5999
5995 for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) { 6000 for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) {
5996 nexleft--; 6001 out.bmv_oflags = (map[i].br_state == XFS_EXT_UNWRITTEN) ?
5997 oflags = (map[i].br_state == XFS_EXT_UNWRITTEN) ?
5998 BMV_OF_PREALLOC : 0; 6002 BMV_OF_PREALLOC : 0;
5999 out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff); 6003 out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff);
6000 out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount); 6004 out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
6005 out.bmv_unused1 = out.bmv_unused2 = 0;
6001 ASSERT(map[i].br_startblock != DELAYSTARTBLOCK); 6006 ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
6002 if (map[i].br_startblock == HOLESTARTBLOCK && 6007 if (map[i].br_startblock == HOLESTARTBLOCK &&
6003 whichfork == XFS_ATTR_FORK) { 6008 whichfork == XFS_ATTR_FORK) {
6004 /* came to the end of attribute fork */ 6009 /* came to the end of attribute fork */
6005 goto unlock_and_return; 6010 goto unlock_and_return;
6006 } else { 6011 } else {
6012 int full = 0; /* user array is full */
6013
6007 if (!xfs_getbmapx_fix_eof_hole(ip, &out, 6014 if (!xfs_getbmapx_fix_eof_hole(ip, &out,
6008 prealloced, bmvend, 6015 prealloced, bmvend,
6009 map[i].br_startblock)) { 6016 map[i].br_startblock)) {
6010 goto unlock_and_return; 6017 goto unlock_and_return;
6011 } 6018 }
6012 6019
6013 /* return either getbmap/getbmapx structure. */ 6020 /* format results & advance arg */
6014 if (interface & BMV_IF_EXTENDED) { 6021 error = formatter(&arg, &out, &full);
6015 struct getbmapx outx; 6022 if (error || full)
6016 6023 goto unlock_and_return;
6017 GETBMAP_CONVERT(out,outx); 6024 nexleft--;
6018 outx.bmv_oflags = oflags;
6019 outx.bmv_unused1 = outx.bmv_unused2 = 0;
6020 if (copy_to_user(ap, &outx,
6021 sizeof(outx))) {
6022 error = XFS_ERROR(EFAULT);
6023 goto unlock_and_return;
6024 }
6025 } else {
6026 if (copy_to_user(ap, &out,
6027 sizeof(out))) {
6028 error = XFS_ERROR(EFAULT);
6029 goto unlock_and_return;
6030 }
6031 }
6032 bmv->bmv_offset = 6025 bmv->bmv_offset =
6033 out.bmv_offset + out.bmv_length; 6026 out.bmv_offset + out.bmv_length;
6034 bmv->bmv_length = MAX((__int64_t)0, 6027 bmv->bmv_length = MAX((__int64_t)0,
6035 (__int64_t)(bmvend - bmv->bmv_offset)); 6028 (__int64_t)(bmvend - bmv->bmv_offset));
6036 bmv->bmv_entries++; 6029 bmv->bmv_entries++;
6037 ap = (interface & BMV_IF_EXTENDED) ?
6038 (void __user *)
6039 ((struct getbmapx __user *)ap + 1) :
6040 (void __user *)
6041 ((struct getbmap __user *)ap + 1);
6042 } 6030 }
6043 } 6031 }
6044 } while (nmap && nexleft && bmv->bmv_length); 6032 } while (nmap && nexleft && bmv->bmv_length);
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index 7c9d12cd7a47..284571c05ed0 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -356,15 +356,18 @@ xfs_bmap_finish(
356 xfs_bmap_free_t *flist, /* i/o: list extents to free */ 356 xfs_bmap_free_t *flist, /* i/o: list extents to free */
357 int *committed); /* xact committed or not */ 357 int *committed); /* xact committed or not */
358 358
359/* bmap to userspace formatter - copy to user & advance pointer */
360typedef int (*xfs_bmap_format_t)(void **, struct getbmapx *, int *);
361
359/* 362/*
360 * Fcntl interface to xfs_bmapi. 363 * Get inode's extents as described in bmv, and format for output.
361 */ 364 */
362int /* error code */ 365int /* error code */
363xfs_getbmap( 366xfs_getbmap(
364 xfs_inode_t *ip, 367 xfs_inode_t *ip,
365 struct getbmap *bmv, /* user bmap structure */ 368 struct getbmapx *bmv, /* user bmap structure */
366 void __user *ap, /* pointer to user's array */ 369 xfs_bmap_format_t formatter, /* format to user */
367 int iflags); /* interface flags */ 370 void *arg); /* formatter arg */
368 371
369/* 372/*
370 * Check if the endoff is outside the last extent. If so the caller will grow 373 * Check if the endoff is outside the last extent. If so the caller will grow
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index 01c0cc88d3f3..df859d62a163 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -114,22 +114,10 @@ struct getbmapx {
114#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ 114#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */
115#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ 115#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */
116#define BMV_IF_VALID (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC) 116#define BMV_IF_VALID (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC)
117#ifdef __KERNEL__
118#define BMV_IF_EXTENDED 0x40000000 /* getpmapx if set */
119#endif
120 117
121/* bmv_oflags values - returned for for each non-header segment */ 118/* bmv_oflags values - returned for for each non-header segment */
122#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ 119#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
123 120
124/* Convert getbmap <-> getbmapx - move fields from p1 to p2. */
125#define GETBMAP_CONVERT(p1,p2) { \
126 p2.bmv_offset = p1.bmv_offset; \
127 p2.bmv_block = p1.bmv_block; \
128 p2.bmv_length = p1.bmv_length; \
129 p2.bmv_count = p1.bmv_count; \
130 p2.bmv_entries = p1.bmv_entries; }
131
132
133/* 121/*
134 * Structure for XFS_IOC_FSSETDM. 122 * Structure for XFS_IOC_FSSETDM.
135 * For use by backup and restore programs to set the XFS on-disk inode 123 * For use by backup and restore programs to set the XFS on-disk inode