[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>
This commit is contained in:
parent
0924b585fc
commit
8a7141a8b9
4 changed files with 71 additions and 78 deletions
|
@ -1249,6 +1249,19 @@ xfs_ioc_setxflags(
|
||||||
return -xfs_ioctl_setattr(ip, &fa, mask);
|
return -xfs_ioctl_setattr(ip, &fa, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC int
|
||||||
|
xfs_getbmap_format(void **ap, struct getbmapx *bmv, int *full)
|
||||||
|
{
|
||||||
|
struct getbmap __user *base = *ap;
|
||||||
|
|
||||||
|
/* copy only getbmap portion (not getbmapx) */
|
||||||
|
if (copy_to_user(base, bmv, sizeof(struct getbmap)))
|
||||||
|
return XFS_ERROR(EFAULT);
|
||||||
|
|
||||||
|
*ap += sizeof(struct getbmap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_ioc_getbmap(
|
xfs_ioc_getbmap(
|
||||||
struct xfs_inode *ip,
|
struct xfs_inode *ip,
|
||||||
|
@ -1256,37 +1269,48 @@ xfs_ioc_getbmap(
|
||||||
unsigned int cmd,
|
unsigned int cmd,
|
||||||
void __user *arg)
|
void __user *arg)
|
||||||
{
|
{
|
||||||
struct getbmap bm;
|
struct getbmapx bmx;
|
||||||
int iflags;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (copy_from_user(&bm, arg, sizeof(bm)))
|
if (copy_from_user(&bmx, arg, sizeof(struct getbmapx)))
|
||||||
return -XFS_ERROR(EFAULT);
|
return -XFS_ERROR(EFAULT);
|
||||||
|
|
||||||
if (bm.bmv_count < 2)
|
if (bmx.bmv_count < 2)
|
||||||
return -XFS_ERROR(EINVAL);
|
return -XFS_ERROR(EINVAL);
|
||||||
|
|
||||||
iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
|
bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
|
||||||
if (ioflags & IO_INVIS)
|
if (ioflags & IO_INVIS)
|
||||||
iflags |= BMV_IF_NO_DMAPI_READ;
|
bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;
|
||||||
|
|
||||||
error = xfs_getbmap(ip, &bm, (struct getbmap __user *)arg+1, iflags);
|
error = xfs_getbmap(ip, &bmx, xfs_getbmap_format,
|
||||||
|
(struct getbmap *)arg+1);
|
||||||
if (error)
|
if (error)
|
||||||
return -error;
|
return -error;
|
||||||
|
|
||||||
if (copy_to_user(arg, &bm, sizeof(bm)))
|
/* copy back header - only size of getbmap */
|
||||||
|
if (copy_to_user(arg, &bmx, sizeof(struct getbmap)))
|
||||||
return -XFS_ERROR(EFAULT);
|
return -XFS_ERROR(EFAULT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC int
|
||||||
|
xfs_getbmapx_format(void **ap, struct getbmapx *bmv, int *full)
|
||||||
|
{
|
||||||
|
struct getbmapx __user *base = *ap;
|
||||||
|
|
||||||
|
if (copy_to_user(base, bmv, sizeof(struct getbmapx)))
|
||||||
|
return XFS_ERROR(EFAULT);
|
||||||
|
|
||||||
|
*ap += sizeof(struct getbmapx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_ioc_getbmapx(
|
xfs_ioc_getbmapx(
|
||||||
struct xfs_inode *ip,
|
struct xfs_inode *ip,
|
||||||
void __user *arg)
|
void __user *arg)
|
||||||
{
|
{
|
||||||
struct getbmapx bmx;
|
struct getbmapx bmx;
|
||||||
struct getbmap bm;
|
|
||||||
int iflags;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (copy_from_user(&bmx, arg, sizeof(bmx)))
|
if (copy_from_user(&bmx, arg, sizeof(bmx)))
|
||||||
|
@ -1295,26 +1319,16 @@ xfs_ioc_getbmapx(
|
||||||
if (bmx.bmv_count < 2)
|
if (bmx.bmv_count < 2)
|
||||||
return -XFS_ERROR(EINVAL);
|
return -XFS_ERROR(EINVAL);
|
||||||
|
|
||||||
/*
|
if (bmx.bmv_iflags & (~BMV_IF_VALID))
|
||||||
* Map input getbmapx structure to a getbmap
|
|
||||||
* structure for xfs_getbmap.
|
|
||||||
*/
|
|
||||||
GETBMAP_CONVERT(bmx, bm);
|
|
||||||
|
|
||||||
iflags = bmx.bmv_iflags;
|
|
||||||
|
|
||||||
if (iflags & (~BMV_IF_VALID))
|
|
||||||
return -XFS_ERROR(EINVAL);
|
return -XFS_ERROR(EINVAL);
|
||||||
|
|
||||||
iflags |= BMV_IF_EXTENDED;
|
error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format,
|
||||||
|
(struct getbmapx *)arg+1);
|
||||||
error = xfs_getbmap(ip, &bm, (struct getbmapx __user *)arg+1, iflags);
|
|
||||||
if (error)
|
if (error)
|
||||||
return -error;
|
return -error;
|
||||||
|
|
||||||
GETBMAP_CONVERT(bm, bmx);
|
/* copy back header */
|
||||||
|
if (copy_to_user(arg, &bmx, sizeof(struct getbmapx)))
|
||||||
if (copy_to_user(arg, &bmx, sizeof(bmx)))
|
|
||||||
return -XFS_ERROR(EFAULT);
|
return -XFS_ERROR(EFAULT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -5811,7 +5811,7 @@ xfs_bunmapi(
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_getbmapx_fix_eof_hole(
|
xfs_getbmapx_fix_eof_hole(
|
||||||
xfs_inode_t *ip, /* xfs incore inode pointer */
|
xfs_inode_t *ip, /* xfs incore inode pointer */
|
||||||
struct getbmap *out, /* output structure */
|
struct getbmapx *out, /* output structure */
|
||||||
int prealloced, /* this is a file with
|
int prealloced, /* this is a file with
|
||||||
* preallocated data space */
|
* preallocated data space */
|
||||||
__int64_t end, /* last block requested */
|
__int64_t end, /* last block requested */
|
||||||
|
@ -5839,14 +5839,18 @@ xfs_getbmapx_fix_eof_hole(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fcntl interface to xfs_bmapi.
|
* Get inode's extents as described in bmv, and format for output.
|
||||||
|
* Calls formatter to fill the user's buffer until all extents
|
||||||
|
* are mapped, until the passed-in bmv->bmv_count slots have
|
||||||
|
* been filled, or until the formatter short-circuits the loop,
|
||||||
|
* if it is tracking filled-in extents on its own.
|
||||||
*/
|
*/
|
||||||
int /* error code */
|
int /* error code */
|
||||||
xfs_getbmap(
|
xfs_getbmap(
|
||||||
xfs_inode_t *ip,
|
xfs_inode_t *ip,
|
||||||
struct getbmap *bmv, /* user bmap structure */
|
struct getbmapx *bmv, /* user bmap structure */
|
||||||
void __user *ap, /* pointer to user's array */
|
xfs_bmap_format_t formatter, /* format to user */
|
||||||
int interface) /* interface flags */
|
void *arg) /* formatter arg */
|
||||||
{
|
{
|
||||||
__int64_t bmvend; /* last block requested */
|
__int64_t bmvend; /* last block requested */
|
||||||
int error; /* return value */
|
int error; /* return value */
|
||||||
|
@ -5859,19 +5863,20 @@ xfs_getbmap(
|
||||||
int nexleft; /* # of user extents left */
|
int nexleft; /* # of user extents left */
|
||||||
int subnex; /* # of bmapi's can do */
|
int subnex; /* # of bmapi's can do */
|
||||||
int nmap; /* number of map entries */
|
int nmap; /* number of map entries */
|
||||||
struct getbmap out; /* output structure */
|
struct getbmapx out; /* output structure */
|
||||||
int whichfork; /* data or attr fork */
|
int whichfork; /* data or attr fork */
|
||||||
int prealloced; /* this is a file with
|
int prealloced; /* this is a file with
|
||||||
* preallocated data space */
|
* preallocated data space */
|
||||||
int sh_unwritten; /* true, if unwritten */
|
int sh_unwritten; /* true, if unwritten */
|
||||||
/* extents listed separately */
|
/* extents listed separately */
|
||||||
|
int iflags; /* interface flags */
|
||||||
int bmapi_flags; /* flags for xfs_bmapi */
|
int bmapi_flags; /* flags for xfs_bmapi */
|
||||||
__int32_t oflags; /* getbmapx bmv_oflags field */
|
|
||||||
|
|
||||||
mp = ip->i_mount;
|
mp = ip->i_mount;
|
||||||
|
iflags = bmv->bmv_iflags;
|
||||||
|
|
||||||
whichfork = interface & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK;
|
whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK;
|
||||||
sh_unwritten = (interface & BMV_IF_PREALLOC) != 0;
|
sh_unwritten = (iflags & BMV_IF_PREALLOC) != 0;
|
||||||
|
|
||||||
/* If the BMV_IF_NO_DMAPI_READ interface bit specified, do not
|
/* If the BMV_IF_NO_DMAPI_READ interface bit specified, do not
|
||||||
* generate a DMAPI read event. Otherwise, if the DM_EVENT_READ
|
* generate a DMAPI read event. Otherwise, if the DM_EVENT_READ
|
||||||
|
@ -5886,7 +5891,7 @@ xfs_getbmap(
|
||||||
* could misinterpret holes in a DMAPI file as true holes,
|
* could misinterpret holes in a DMAPI file as true holes,
|
||||||
* when in fact they may represent offline user data.
|
* when in fact they may represent offline user data.
|
||||||
*/
|
*/
|
||||||
if ((interface & BMV_IF_NO_DMAPI_READ) == 0 &&
|
if ((iflags & BMV_IF_NO_DMAPI_READ) == 0 &&
|
||||||
DM_EVENT_ENABLED(ip, DM_EVENT_READ) &&
|
DM_EVENT_ENABLED(ip, DM_EVENT_READ) &&
|
||||||
whichfork == XFS_DATA_FORK) {
|
whichfork == XFS_DATA_FORK) {
|
||||||
error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL);
|
error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL);
|
||||||
|
@ -5993,52 +5998,35 @@ xfs_getbmap(
|
||||||
ASSERT(nmap <= subnex);
|
ASSERT(nmap <= subnex);
|
||||||
|
|
||||||
for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) {
|
for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) {
|
||||||
nexleft--;
|
out.bmv_oflags = (map[i].br_state == XFS_EXT_UNWRITTEN) ?
|
||||||
oflags = (map[i].br_state == XFS_EXT_UNWRITTEN) ?
|
|
||||||
BMV_OF_PREALLOC : 0;
|
BMV_OF_PREALLOC : 0;
|
||||||
out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff);
|
out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff);
|
||||||
out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
|
out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
|
||||||
|
out.bmv_unused1 = out.bmv_unused2 = 0;
|
||||||
ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
|
ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
|
||||||
if (map[i].br_startblock == HOLESTARTBLOCK &&
|
if (map[i].br_startblock == HOLESTARTBLOCK &&
|
||||||
whichfork == XFS_ATTR_FORK) {
|
whichfork == XFS_ATTR_FORK) {
|
||||||
/* came to the end of attribute fork */
|
/* came to the end of attribute fork */
|
||||||
goto unlock_and_return;
|
goto unlock_and_return;
|
||||||
} else {
|
} else {
|
||||||
|
int full = 0; /* user array is full */
|
||||||
|
|
||||||
if (!xfs_getbmapx_fix_eof_hole(ip, &out,
|
if (!xfs_getbmapx_fix_eof_hole(ip, &out,
|
||||||
prealloced, bmvend,
|
prealloced, bmvend,
|
||||||
map[i].br_startblock)) {
|
map[i].br_startblock)) {
|
||||||
goto unlock_and_return;
|
goto unlock_and_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return either getbmap/getbmapx structure. */
|
/* format results & advance arg */
|
||||||
if (interface & BMV_IF_EXTENDED) {
|
error = formatter(&arg, &out, &full);
|
||||||
struct getbmapx outx;
|
if (error || full)
|
||||||
|
|
||||||
GETBMAP_CONVERT(out,outx);
|
|
||||||
outx.bmv_oflags = oflags;
|
|
||||||
outx.bmv_unused1 = outx.bmv_unused2 = 0;
|
|
||||||
if (copy_to_user(ap, &outx,
|
|
||||||
sizeof(outx))) {
|
|
||||||
error = XFS_ERROR(EFAULT);
|
|
||||||
goto unlock_and_return;
|
goto unlock_and_return;
|
||||||
}
|
nexleft--;
|
||||||
} else {
|
|
||||||
if (copy_to_user(ap, &out,
|
|
||||||
sizeof(out))) {
|
|
||||||
error = XFS_ERROR(EFAULT);
|
|
||||||
goto unlock_and_return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bmv->bmv_offset =
|
bmv->bmv_offset =
|
||||||
out.bmv_offset + out.bmv_length;
|
out.bmv_offset + out.bmv_length;
|
||||||
bmv->bmv_length = MAX((__int64_t)0,
|
bmv->bmv_length = MAX((__int64_t)0,
|
||||||
(__int64_t)(bmvend - bmv->bmv_offset));
|
(__int64_t)(bmvend - bmv->bmv_offset));
|
||||||
bmv->bmv_entries++;
|
bmv->bmv_entries++;
|
||||||
ap = (interface & BMV_IF_EXTENDED) ?
|
|
||||||
(void __user *)
|
|
||||||
((struct getbmapx __user *)ap + 1) :
|
|
||||||
(void __user *)
|
|
||||||
((struct getbmap __user *)ap + 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (nmap && nexleft && bmv->bmv_length);
|
} while (nmap && nexleft && bmv->bmv_length);
|
||||||
|
|
|
@ -356,15 +356,18 @@ xfs_bmap_finish(
|
||||||
xfs_bmap_free_t *flist, /* i/o: list extents to free */
|
xfs_bmap_free_t *flist, /* i/o: list extents to free */
|
||||||
int *committed); /* xact committed or not */
|
int *committed); /* xact committed or not */
|
||||||
|
|
||||||
|
/* bmap to userspace formatter - copy to user & advance pointer */
|
||||||
|
typedef int (*xfs_bmap_format_t)(void **, struct getbmapx *, int *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fcntl interface to xfs_bmapi.
|
* Get inode's extents as described in bmv, and format for output.
|
||||||
*/
|
*/
|
||||||
int /* error code */
|
int /* error code */
|
||||||
xfs_getbmap(
|
xfs_getbmap(
|
||||||
xfs_inode_t *ip,
|
xfs_inode_t *ip,
|
||||||
struct getbmap *bmv, /* user bmap structure */
|
struct getbmapx *bmv, /* user bmap structure */
|
||||||
void __user *ap, /* pointer to user's array */
|
xfs_bmap_format_t formatter, /* format to user */
|
||||||
int iflags); /* interface flags */
|
void *arg); /* formatter arg */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the endoff is outside the last extent. If so the caller will grow
|
* Check if the endoff is outside the last extent. If so the caller will grow
|
||||||
|
|
|
@ -114,22 +114,10 @@ struct getbmapx {
|
||||||
#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */
|
#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */
|
||||||
#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */
|
#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */
|
||||||
#define BMV_IF_VALID (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC)
|
#define BMV_IF_VALID (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC)
|
||||||
#ifdef __KERNEL__
|
|
||||||
#define BMV_IF_EXTENDED 0x40000000 /* getpmapx if set */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* bmv_oflags values - returned for for each non-header segment */
|
/* bmv_oflags values - returned for for each non-header segment */
|
||||||
#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
|
#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
|
||||||
|
|
||||||
/* Convert getbmap <-> getbmapx - move fields from p1 to p2. */
|
|
||||||
#define GETBMAP_CONVERT(p1,p2) { \
|
|
||||||
p2.bmv_offset = p1.bmv_offset; \
|
|
||||||
p2.bmv_block = p1.bmv_block; \
|
|
||||||
p2.bmv_length = p1.bmv_length; \
|
|
||||||
p2.bmv_count = p1.bmv_count; \
|
|
||||||
p2.bmv_entries = p1.bmv_entries; }
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure for XFS_IOC_FSSETDM.
|
* Structure for XFS_IOC_FSSETDM.
|
||||||
* For use by backup and restore programs to set the XFS on-disk inode
|
* For use by backup and restore programs to set the XFS on-disk inode
|
||||||
|
|
Loading…
Reference in a new issue