Commit 2810bd68 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: convert bulkstat to new iwalk infrastructure

Create a new ibulk structure incore to help us deal with bulk inode stat
state tracking and then convert the bulkstat code to use the new iwalk
iterator.  This disentangles inode walking from bulk stat control for
simpler code and enables us to isolate the formatter functions to the
ioctl handling code.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
parent f16fe3ec
......@@ -12,6 +12,7 @@
#include "xfs_mount.h"
#include "xfs_inode.h"
#include "xfs_rtalloc.h"
#include "xfs_iwalk.h"
#include "xfs_itable.h"
#include "xfs_error.h"
#include "xfs_attr.h"
......@@ -712,16 +713,29 @@ xfs_ioc_space(
return error;
}
/* Return 0 on success or positive error */
int
xfs_bulkstat_one_fmt(
struct xfs_ibulk *breq,
const struct xfs_bstat *bstat)
{
if (copy_to_user(breq->ubuffer, bstat, sizeof(*bstat)))
return -EFAULT;
return xfs_ibulk_advance(breq, sizeof(struct xfs_bstat));
}
STATIC int
xfs_ioc_bulkstat(
xfs_mount_t *mp,
unsigned int cmd,
void __user *arg)
{
xfs_fsop_bulkreq_t bulkreq;
int count; /* # of records returned */
xfs_ino_t inlast; /* last inode number */
int done;
struct xfs_fsop_bulkreq bulkreq;
struct xfs_ibulk breq = {
.mp = mp,
.ocount = 0,
};
xfs_ino_t lastino;
int error;
/* done = 1 if there are more stats to get and if bulkstat */
......@@ -736,35 +750,57 @@ xfs_ioc_bulkstat(
if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t)))
return -EFAULT;
if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
if (copy_from_user(&lastino, bulkreq.lastip, sizeof(__s64)))
return -EFAULT;
if ((count = bulkreq.icount) <= 0)
if (bulkreq.icount <= 0)
return -EINVAL;
if (bulkreq.ubuffer == NULL)
return -EINVAL;
if (cmd == XFS_IOC_FSINUMBERS)
error = xfs_inumbers(mp, &inlast, &count,
breq.ubuffer = bulkreq.ubuffer;
breq.icount = bulkreq.icount;
/*
* FSBULKSTAT_SINGLE expects that *lastip contains the inode number
* that we want to stat. However, FSINUMBERS and FSBULKSTAT expect
* that *lastip contains either zero or the number of the last inode to
* be examined by the previous call and return results starting with
* the next inode after that. The new bulk request back end functions
* take the inode to start with, so we have to compute the startino
* parameter from lastino to maintain correct function. lastino == 0
* is a special case because it has traditionally meant "first inode
* in filesystem".
*/
if (cmd == XFS_IOC_FSINUMBERS) {
int count = breq.icount;
breq.startino = lastino;
error = xfs_inumbers(mp, &breq.startino, &count,
bulkreq.ubuffer, xfs_inumbers_fmt);
else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
error = xfs_bulkstat_one(mp, inlast, bulkreq.ubuffer,
sizeof(xfs_bstat_t), NULL, &done);
else /* XFS_IOC_FSBULKSTAT */
error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one,
sizeof(xfs_bstat_t), bulkreq.ubuffer,
&done);
breq.ocount = count;
lastino = breq.startino;
} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
breq.startino = lastino;
breq.icount = 1;
error = xfs_bulkstat_one(&breq, xfs_bulkstat_one_fmt);
lastino = breq.startino;
} else { /* XFS_IOC_FSBULKSTAT */
breq.startino = lastino ? lastino + 1 : 0;
error = xfs_bulkstat(&breq, xfs_bulkstat_one_fmt);
lastino = breq.startino - 1;
}
if (error)
return error;
if (bulkreq.lastip != NULL &&
copy_to_user(bulkreq.lastip, &inlast, sizeof(xfs_ino_t)))
copy_to_user(bulkreq.lastip, &lastino, sizeof(xfs_ino_t)))
return -EFAULT;
if (bulkreq.ocount != NULL &&
copy_to_user(bulkreq.ocount, &count, sizeof(count)))
copy_to_user(bulkreq.ocount, &breq.ocount, sizeof(__s32)))
return -EFAULT;
return 0;
......
......@@ -77,4 +77,9 @@ xfs_set_dmattrs(
uint evmask,
uint16_t state);
struct xfs_ibulk;
struct xfs_bstat;
int xfs_bulkstat_one_fmt(struct xfs_ibulk *breq, const struct xfs_bstat *bstat);
#endif
......@@ -13,6 +13,7 @@
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_inode.h"
#include "xfs_iwalk.h"
#include "xfs_itable.h"
#include "xfs_fsops.h"
#include "xfs_rtalloc.h"
......@@ -167,15 +168,10 @@ xfs_bstime_store_compat(
/* Return 0 on success or positive error (to xfs_bulkstat()) */
STATIC int
xfs_bulkstat_one_fmt_compat(
void __user *ubuffer,
int ubsize,
int *ubused,
const xfs_bstat_t *buffer)
struct xfs_ibulk *breq,
const struct xfs_bstat *buffer)
{
compat_xfs_bstat_t __user *p32 = ubuffer;
if (ubsize < sizeof(*p32))
return -ENOMEM;
struct compat_xfs_bstat __user *p32 = breq->ubuffer;
if (put_user(buffer->bs_ino, &p32->bs_ino) ||
put_user(buffer->bs_mode, &p32->bs_mode) ||
......@@ -200,23 +196,8 @@ xfs_bulkstat_one_fmt_compat(
put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
put_user(buffer->bs_aextents, &p32->bs_aextents))
return -EFAULT;
if (ubused)
*ubused = sizeof(*p32);
return 0;
}
STATIC int
xfs_bulkstat_one_compat(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t ino, /* inode number to get data for */
void __user *buffer, /* buffer to place output in */
int ubsize, /* size of buffer */
int *ubused, /* bytes used by me */
int *stat) /* BULKSTAT_RV_... */
{
return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
xfs_bulkstat_one_fmt_compat,
ubused, stat);
return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_bstat));
}
/* copied from xfs_ioctl.c */
......@@ -227,10 +208,12 @@ xfs_compat_ioc_bulkstat(
compat_xfs_fsop_bulkreq_t __user *p32)
{
u32 addr;
xfs_fsop_bulkreq_t bulkreq;
int count; /* # of records returned */
xfs_ino_t inlast; /* last inode number */
int done;
struct xfs_fsop_bulkreq bulkreq;
struct xfs_ibulk breq = {
.mp = mp,
.ocount = 0,
};
xfs_ino_t lastino;
int error;
/*
......@@ -240,8 +223,7 @@ xfs_compat_ioc_bulkstat(
* functions and structure size are the correct ones to use ...
*/
inumbers_fmt_pf inumbers_func = xfs_inumbers_fmt_compat;
bulkstat_one_pf bs_one_func = xfs_bulkstat_one_compat;
size_t bs_one_size = sizeof(struct compat_xfs_bstat);
bulkstat_one_fmt_pf bs_one_func = xfs_bulkstat_one_fmt_compat;
#ifdef CONFIG_X86_X32
if (in_x32_syscall()) {
......@@ -254,8 +236,7 @@ xfs_compat_ioc_bulkstat(
* x32 userspace expects.
*/
inumbers_func = xfs_inumbers_fmt;
bs_one_func = xfs_bulkstat_one;
bs_one_size = sizeof(struct xfs_bstat);
bs_one_func = xfs_bulkstat_one_fmt;
}
#endif
......@@ -279,38 +260,58 @@ xfs_compat_ioc_bulkstat(
return -EFAULT;
bulkreq.ocount = compat_ptr(addr);
if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
if (copy_from_user(&lastino, bulkreq.lastip, sizeof(__s64)))
return -EFAULT;
if ((count = bulkreq.icount) <= 0)
if (bulkreq.icount <= 0)
return -EINVAL;
if (bulkreq.ubuffer == NULL)
return -EINVAL;
breq.ubuffer = bulkreq.ubuffer;
breq.icount = bulkreq.icount;
/*
* FSBULKSTAT_SINGLE expects that *lastip contains the inode number
* that we want to stat. However, FSINUMBERS and FSBULKSTAT expect
* that *lastip contains either zero or the number of the last inode to
* be examined by the previous call and return results starting with
* the next inode after that. The new bulk request back end functions
* take the inode to start with, so we have to compute the startino
* parameter from lastino to maintain correct function. lastino == 0
* is a special case because it has traditionally meant "first inode
* in filesystem".
*/
if (cmd == XFS_IOC_FSINUMBERS_32) {
error = xfs_inumbers(mp, &inlast, &count,
int count = breq.icount;
breq.startino = lastino;
error = xfs_inumbers(mp, &breq.startino, &count,
bulkreq.ubuffer, inumbers_func);
breq.ocount = count;
lastino = breq.startino;
} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
int res;
error = bs_one_func(mp, inlast, bulkreq.ubuffer,
bs_one_size, NULL, &res);
breq.startino = lastino;
breq.icount = 1;
error = xfs_bulkstat_one(&breq, bs_one_func);
lastino = breq.startino;
} else if (cmd == XFS_IOC_FSBULKSTAT_32) {
error = xfs_bulkstat(mp, &inlast, &count,
bs_one_func, bs_one_size,
bulkreq.ubuffer, &done);
} else
breq.startino = lastino ? lastino + 1 : 0;
error = xfs_bulkstat(&breq, bs_one_func);
lastino = breq.startino - 1;
} else {
error = -EINVAL;
}
if (error)
return error;
if (bulkreq.lastip != NULL &&
copy_to_user(bulkreq.lastip, &inlast, sizeof(xfs_ino_t)))
copy_to_user(bulkreq.lastip, &lastino, sizeof(xfs_ino_t)))
return -EFAULT;
if (bulkreq.ocount != NULL &&
copy_to_user(bulkreq.ocount, &count, sizeof(count)))
copy_to_user(bulkreq.ocount, &breq.ocount, sizeof(__s32)))
return -EFAULT;
return 0;
......
This diff is collapsed.
......@@ -5,63 +5,43 @@
#ifndef __XFS_ITABLE_H__
#define __XFS_ITABLE_H__
/*
* xfs_bulkstat() is used to fill in xfs_bstat structures as well as dm_stat
* structures (by the dmi library). This is a pointer to a formatter function
* that will iget the inode and fill in the appropriate structure.
* see xfs_bulkstat_one() and xfs_dm_bulkstat_one() in dmapi_xfs.c
*/
typedef int (*bulkstat_one_pf)(struct xfs_mount *mp,
xfs_ino_t ino,
void __user *buffer,
int ubsize,
int *ubused,
int *stat);
/* In-memory representation of a userspace request for batch inode data. */
struct xfs_ibulk {
struct xfs_mount *mp;
void __user *ubuffer; /* user output buffer */
xfs_ino_t startino; /* start with this inode */
unsigned int icount; /* number of elements in ubuffer */
unsigned int ocount; /* number of records returned */
};
/* Return value that means we want to abort the walk. */
#define XFS_IBULK_ABORT (XFS_IWALK_ABORT)
/*
* Values for stat return value.
* Advance the user buffer pointer by one record of the given size. If the
* buffer is now full, return the appropriate error code.
*/
#define BULKSTAT_RV_NOTHING 0
#define BULKSTAT_RV_DIDONE 1
#define BULKSTAT_RV_GIVEUP 2
static inline int
xfs_ibulk_advance(
struct xfs_ibulk *breq,
size_t bytes)
{
char __user *b = breq->ubuffer;
breq->ubuffer = b + bytes;
breq->ocount++;
return breq->ocount == breq->icount ? XFS_IBULK_ABORT : 0;
}
/*
* Return stat information in bulk (by-inode) for the filesystem.
*/
int /* error status */
xfs_bulkstat(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t *lastino, /* last inode returned */
int *count, /* size of buffer/count returned */
bulkstat_one_pf formatter, /* func that'd fill a single buf */
size_t statstruct_size,/* sizeof struct that we're filling */
char __user *ubuffer,/* buffer with inode stats */
int *done); /* 1 if there are more stats to get */
typedef int (*bulkstat_one_fmt_pf)( /* used size in bytes or negative error */
void __user *ubuffer, /* buffer to write to */
int ubsize, /* remaining user buffer sz */
int *ubused, /* bytes used by formatter */
const xfs_bstat_t *buffer); /* buffer to read from */
int
xfs_bulkstat_one_int(
xfs_mount_t *mp,
xfs_ino_t ino,
void __user *buffer,
int ubsize,
bulkstat_one_fmt_pf formatter,
int *ubused,
int *stat);
typedef int (*bulkstat_one_fmt_pf)(struct xfs_ibulk *breq,
const struct xfs_bstat *bstat);
int
xfs_bulkstat_one(
xfs_mount_t *mp,
xfs_ino_t ino,
void __user *buffer,
int ubsize,
int *ubused,
int *stat);
int xfs_bulkstat_one(struct xfs_ibulk *breq, bulkstat_one_fmt_pf formatter);
int xfs_bulkstat(struct xfs_ibulk *breq, bulkstat_one_fmt_pf formatter);
typedef int (*inumbers_fmt_pf)(
void __user *ubuffer, /* buffer to write to */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment