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 @@ ...@@ -12,6 +12,7 @@
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_rtalloc.h" #include "xfs_rtalloc.h"
#include "xfs_iwalk.h"
#include "xfs_itable.h" #include "xfs_itable.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_attr.h" #include "xfs_attr.h"
...@@ -712,16 +713,29 @@ xfs_ioc_space( ...@@ -712,16 +713,29 @@ xfs_ioc_space(
return error; 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 STATIC int
xfs_ioc_bulkstat( xfs_ioc_bulkstat(
xfs_mount_t *mp, xfs_mount_t *mp,
unsigned int cmd, unsigned int cmd,
void __user *arg) void __user *arg)
{ {
xfs_fsop_bulkreq_t bulkreq; struct xfs_fsop_bulkreq bulkreq;
int count; /* # of records returned */ struct xfs_ibulk breq = {
xfs_ino_t inlast; /* last inode number */ .mp = mp,
int done; .ocount = 0,
};
xfs_ino_t lastino;
int error; int error;
/* done = 1 if there are more stats to get and if bulkstat */ /* done = 1 if there are more stats to get and if bulkstat */
...@@ -736,35 +750,57 @@ xfs_ioc_bulkstat( ...@@ -736,35 +750,57 @@ xfs_ioc_bulkstat(
if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t))) if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t)))
return -EFAULT; return -EFAULT;
if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) if (copy_from_user(&lastino, bulkreq.lastip, sizeof(__s64)))
return -EFAULT; return -EFAULT;
if ((count = bulkreq.icount) <= 0) if (bulkreq.icount <= 0)
return -EINVAL; return -EINVAL;
if (bulkreq.ubuffer == NULL) if (bulkreq.ubuffer == NULL)
return -EINVAL; return -EINVAL;
if (cmd == XFS_IOC_FSINUMBERS) breq.ubuffer = bulkreq.ubuffer;
error = xfs_inumbers(mp, &inlast, &count, 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); bulkreq.ubuffer, xfs_inumbers_fmt);
else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) breq.ocount = count;
error = xfs_bulkstat_one(mp, inlast, bulkreq.ubuffer, lastino = breq.startino;
sizeof(xfs_bstat_t), NULL, &done); } else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
else /* XFS_IOC_FSBULKSTAT */ breq.startino = lastino;
error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one, breq.icount = 1;
sizeof(xfs_bstat_t), bulkreq.ubuffer, error = xfs_bulkstat_one(&breq, xfs_bulkstat_one_fmt);
&done); 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) if (error)
return error; return error;
if (bulkreq.lastip != NULL && 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; return -EFAULT;
if (bulkreq.ocount != NULL && if (bulkreq.ocount != NULL &&
copy_to_user(bulkreq.ocount, &count, sizeof(count))) copy_to_user(bulkreq.ocount, &breq.ocount, sizeof(__s32)))
return -EFAULT; return -EFAULT;
return 0; return 0;
......
...@@ -77,4 +77,9 @@ xfs_set_dmattrs( ...@@ -77,4 +77,9 @@ xfs_set_dmattrs(
uint evmask, uint evmask,
uint16_t state); uint16_t state);
struct xfs_ibulk;
struct xfs_bstat;
int xfs_bulkstat_one_fmt(struct xfs_ibulk *breq, const struct xfs_bstat *bstat);
#endif #endif
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_iwalk.h"
#include "xfs_itable.h" #include "xfs_itable.h"
#include "xfs_fsops.h" #include "xfs_fsops.h"
#include "xfs_rtalloc.h" #include "xfs_rtalloc.h"
...@@ -167,15 +168,10 @@ xfs_bstime_store_compat( ...@@ -167,15 +168,10 @@ xfs_bstime_store_compat(
/* Return 0 on success or positive error (to xfs_bulkstat()) */ /* Return 0 on success or positive error (to xfs_bulkstat()) */
STATIC int STATIC int
xfs_bulkstat_one_fmt_compat( xfs_bulkstat_one_fmt_compat(
void __user *ubuffer, struct xfs_ibulk *breq,
int ubsize, const struct xfs_bstat *buffer)
int *ubused,
const xfs_bstat_t *buffer)
{ {
compat_xfs_bstat_t __user *p32 = ubuffer; struct compat_xfs_bstat __user *p32 = breq->ubuffer;
if (ubsize < sizeof(*p32))
return -ENOMEM;
if (put_user(buffer->bs_ino, &p32->bs_ino) || if (put_user(buffer->bs_ino, &p32->bs_ino) ||
put_user(buffer->bs_mode, &p32->bs_mode) || put_user(buffer->bs_mode, &p32->bs_mode) ||
...@@ -200,23 +196,8 @@ xfs_bulkstat_one_fmt_compat( ...@@ -200,23 +196,8 @@ xfs_bulkstat_one_fmt_compat(
put_user(buffer->bs_dmstate, &p32->bs_dmstate) || put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
put_user(buffer->bs_aextents, &p32->bs_aextents)) put_user(buffer->bs_aextents, &p32->bs_aextents))
return -EFAULT; return -EFAULT;
if (ubused)
*ubused = sizeof(*p32);
return 0;
}
STATIC int return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_bstat));
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);
} }
/* copied from xfs_ioctl.c */ /* copied from xfs_ioctl.c */
...@@ -227,10 +208,12 @@ xfs_compat_ioc_bulkstat( ...@@ -227,10 +208,12 @@ xfs_compat_ioc_bulkstat(
compat_xfs_fsop_bulkreq_t __user *p32) compat_xfs_fsop_bulkreq_t __user *p32)
{ {
u32 addr; u32 addr;
xfs_fsop_bulkreq_t bulkreq; struct xfs_fsop_bulkreq bulkreq;
int count; /* # of records returned */ struct xfs_ibulk breq = {
xfs_ino_t inlast; /* last inode number */ .mp = mp,
int done; .ocount = 0,
};
xfs_ino_t lastino;
int error; int error;
/* /*
...@@ -240,8 +223,7 @@ xfs_compat_ioc_bulkstat( ...@@ -240,8 +223,7 @@ xfs_compat_ioc_bulkstat(
* functions and structure size are the correct ones to use ... * functions and structure size are the correct ones to use ...
*/ */
inumbers_fmt_pf inumbers_func = xfs_inumbers_fmt_compat; inumbers_fmt_pf inumbers_func = xfs_inumbers_fmt_compat;
bulkstat_one_pf bs_one_func = xfs_bulkstat_one_compat; bulkstat_one_fmt_pf bs_one_func = xfs_bulkstat_one_fmt_compat;
size_t bs_one_size = sizeof(struct compat_xfs_bstat);
#ifdef CONFIG_X86_X32 #ifdef CONFIG_X86_X32
if (in_x32_syscall()) { if (in_x32_syscall()) {
...@@ -254,8 +236,7 @@ xfs_compat_ioc_bulkstat( ...@@ -254,8 +236,7 @@ xfs_compat_ioc_bulkstat(
* x32 userspace expects. * x32 userspace expects.
*/ */
inumbers_func = xfs_inumbers_fmt; inumbers_func = xfs_inumbers_fmt;
bs_one_func = xfs_bulkstat_one; bs_one_func = xfs_bulkstat_one_fmt;
bs_one_size = sizeof(struct xfs_bstat);
} }
#endif #endif
...@@ -279,38 +260,58 @@ xfs_compat_ioc_bulkstat( ...@@ -279,38 +260,58 @@ xfs_compat_ioc_bulkstat(
return -EFAULT; return -EFAULT;
bulkreq.ocount = compat_ptr(addr); 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; return -EFAULT;
if ((count = bulkreq.icount) <= 0) if (bulkreq.icount <= 0)
return -EINVAL; return -EINVAL;
if (bulkreq.ubuffer == NULL) if (bulkreq.ubuffer == NULL)
return -EINVAL; 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) { 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); bulkreq.ubuffer, inumbers_func);
breq.ocount = count;
lastino = breq.startino;
} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) { } else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
int res; breq.startino = lastino;
breq.icount = 1;
error = bs_one_func(mp, inlast, bulkreq.ubuffer, error = xfs_bulkstat_one(&breq, bs_one_func);
bs_one_size, NULL, &res); lastino = breq.startino;
} else if (cmd == XFS_IOC_FSBULKSTAT_32) { } else if (cmd == XFS_IOC_FSBULKSTAT_32) {
error = xfs_bulkstat(mp, &inlast, &count, breq.startino = lastino ? lastino + 1 : 0;
bs_one_func, bs_one_size, error = xfs_bulkstat(&breq, bs_one_func);
bulkreq.ubuffer, &done); lastino = breq.startino - 1;
} else } else {
error = -EINVAL; error = -EINVAL;
}
if (error) if (error)
return error; return error;
if (bulkreq.lastip != NULL && 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; return -EFAULT;
if (bulkreq.ocount != NULL && if (bulkreq.ocount != NULL &&
copy_to_user(bulkreq.ocount, &count, sizeof(count))) copy_to_user(bulkreq.ocount, &breq.ocount, sizeof(__s32)))
return -EFAULT; return -EFAULT;
return 0; return 0;
......
This diff is collapsed.
...@@ -5,63 +5,43 @@ ...@@ -5,63 +5,43 @@
#ifndef __XFS_ITABLE_H__ #ifndef __XFS_ITABLE_H__
#define __XFS_ITABLE_H__ #define __XFS_ITABLE_H__
/* /* In-memory representation of a userspace request for batch inode data. */
* xfs_bulkstat() is used to fill in xfs_bstat structures as well as dm_stat struct xfs_ibulk {
* structures (by the dmi library). This is a pointer to a formatter function struct xfs_mount *mp;
* that will iget the inode and fill in the appropriate structure. void __user *ubuffer; /* user output buffer */
* see xfs_bulkstat_one() and xfs_dm_bulkstat_one() in dmapi_xfs.c xfs_ino_t startino; /* start with this inode */
*/ unsigned int icount; /* number of elements in ubuffer */
typedef int (*bulkstat_one_pf)(struct xfs_mount *mp, unsigned int ocount; /* number of records returned */
xfs_ino_t ino, };
void __user *buffer,
int ubsize, /* Return value that means we want to abort the walk. */
int *ubused, #define XFS_IBULK_ABORT (XFS_IWALK_ABORT)
int *stat);
/* /*
* 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 static inline int
#define BULKSTAT_RV_DIDONE 1 xfs_ibulk_advance(
#define BULKSTAT_RV_GIVEUP 2 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. * 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 */ typedef int (*bulkstat_one_fmt_pf)(struct xfs_ibulk *breq,
void __user *ubuffer, /* buffer to write to */ const struct xfs_bstat *bstat);
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);
int int xfs_bulkstat_one(struct xfs_ibulk *breq, bulkstat_one_fmt_pf formatter);
xfs_bulkstat_one( int xfs_bulkstat(struct xfs_ibulk *breq, bulkstat_one_fmt_pf formatter);
xfs_mount_t *mp,
xfs_ino_t ino,
void __user *buffer,
int ubsize,
int *ubused,
int *stat);
typedef int (*inumbers_fmt_pf)( typedef int (*inumbers_fmt_pf)(
void __user *ubuffer, /* buffer to write to */ 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