xfs: refactor INUMBERS to use iwalk functions

Now that we have generic functions to walk inode records, refactor the
INUMBERS implementation to use it.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
This commit is contained in:
Darrick J. Wong 2019-07-02 09:39:43 -07:00
parent 04b8fba2e1
commit 677717fbd4
5 changed files with 93 additions and 150 deletions

View File

@ -724,6 +724,16 @@ xfs_bulkstat_one_fmt(
return xfs_ibulk_advance(breq, sizeof(struct xfs_bstat));
}
int
xfs_inumbers_fmt(
struct xfs_ibulk *breq,
const struct xfs_inogrp *igrp)
{
if (copy_to_user(breq->ubuffer, igrp, sizeof(*igrp)))
return -EFAULT;
return xfs_ibulk_advance(breq, sizeof(struct xfs_inogrp));
}
STATIC int
xfs_ioc_bulkstat(
xfs_mount_t *mp,
@ -774,13 +784,9 @@ xfs_ioc_bulkstat(
* 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);
breq.ocount = count;
lastino = breq.startino;
breq.startino = lastino ? lastino + 1 : 0;
error = xfs_inumbers(&breq, xfs_inumbers_fmt);
lastino = breq.startino - 1;
} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
breq.startino = lastino;
breq.icount = 1;

View File

@ -79,7 +79,9 @@ xfs_set_dmattrs(
struct xfs_ibulk;
struct xfs_bstat;
struct xfs_inogrp;
int xfs_bulkstat_one_fmt(struct xfs_ibulk *breq, const struct xfs_bstat *bstat);
int xfs_inumbers_fmt(struct xfs_ibulk *breq, const struct xfs_inogrp *igrp);
#endif

View File

@ -81,22 +81,17 @@ xfs_compat_growfs_rt_copyin(
STATIC int
xfs_inumbers_fmt_compat(
void __user *ubuffer,
const struct xfs_inogrp *buffer,
long count,
long *written)
struct xfs_ibulk *breq,
const struct xfs_inogrp *igrp)
{
compat_xfs_inogrp_t __user *p32 = ubuffer;
long i;
struct compat_xfs_inogrp __user *p32 = breq->ubuffer;
for (i = 0; i < count; i++) {
if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) ||
put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) ||
put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask))
return -EFAULT;
}
*written = count * sizeof(*p32);
return 0;
if (put_user(igrp->xi_startino, &p32->xi_startino) ||
put_user(igrp->xi_alloccount, &p32->xi_alloccount) ||
put_user(igrp->xi_allocmask, &p32->xi_allocmask))
return -EFAULT;
return xfs_ibulk_advance(breq, sizeof(struct compat_xfs_inogrp));
}
#else
@ -222,7 +217,7 @@ xfs_compat_ioc_bulkstat(
* to userpace memory via bulkreq.ubuffer. Normally the compat
* 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_fmt_pf bs_one_func = xfs_bulkstat_one_fmt_compat;
#ifdef CONFIG_X86_X32
@ -284,13 +279,9 @@ xfs_compat_ioc_bulkstat(
* in filesystem".
*/
if (cmd == XFS_IOC_FSINUMBERS_32) {
int count = breq.icount;
breq.startino = lastino;
error = xfs_inumbers(mp, &breq.startino, &count,
bulkreq.ubuffer, inumbers_func);
breq.ocount = count;
lastino = breq.startino;
breq.startino = lastino ? lastino + 1 : 0;
error = xfs_inumbers(&breq, inumbers_func);
lastino = breq.startino - 1;
} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
breq.startino = lastino;
breq.icount = 1;

View File

@ -265,121 +265,81 @@ xfs_bulkstat(
return error;
}
int
xfs_inumbers_fmt(
void __user *ubuffer, /* buffer to write to */
const struct xfs_inogrp *buffer, /* buffer to read from */
long count, /* # of elements to read */
long *written) /* # of bytes written */
struct xfs_inumbers_chunk {
inumbers_fmt_pf formatter;
struct xfs_ibulk *breq;
};
/*
* INUMBERS
* ========
* This is how we export inode btree records to userspace, so that XFS tools
* can figure out where inodes are allocated.
*/
/*
* Format the inode group structure and report it somewhere.
*
* Similar to xfs_bulkstat_one_int, lastino is the inode cursor as we walk
* through the filesystem so we move it forward unless there was a runtime
* error. If the formatter tells us the buffer is now full we also move the
* cursor forward and abort the walk.
*/
STATIC int
xfs_inumbers_walk(
struct xfs_mount *mp,
struct xfs_trans *tp,
xfs_agnumber_t agno,
const struct xfs_inobt_rec_incore *irec,
void *data)
{
if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer)))
return -EFAULT;
*written = count * sizeof(*buffer);
return 0;
struct xfs_inogrp inogrp = {
.xi_startino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino),
.xi_alloccount = irec->ir_count - irec->ir_freecount,
.xi_allocmask = ~irec->ir_free,
};
struct xfs_inumbers_chunk *ic = data;
xfs_agino_t agino;
int error;
error = ic->formatter(ic->breq, &inogrp);
if (error && error != XFS_IBULK_ABORT)
return error;
agino = irec->ir_startino + XFS_INODES_PER_CHUNK;
ic->breq->startino = XFS_AGINO_TO_INO(mp, agno, agino);
return error;
}
/*
* Return inode number table for the filesystem.
*/
int /* error status */
int
xfs_inumbers(
struct xfs_mount *mp,/* mount point for filesystem */
xfs_ino_t *lastino,/* last inode returned */
int *count,/* size of buffer/count returned */
void __user *ubuffer,/* buffer with inode descriptions */
struct xfs_ibulk *breq,
inumbers_fmt_pf formatter)
{
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, *lastino);
xfs_agino_t agino = XFS_INO_TO_AGINO(mp, *lastino);
struct xfs_btree_cur *cur = NULL;
struct xfs_buf *agbp = NULL;
struct xfs_inogrp *buffer;
int bcount;
int left = *count;
int bufidx = 0;
struct xfs_inumbers_chunk ic = {
.formatter = formatter,
.breq = breq,
};
int error = 0;
*count = 0;
if (agno >= mp->m_sb.sb_agcount ||
*lastino != XFS_AGINO_TO_INO(mp, agno, agino))
return error;
if (xfs_bulkstat_already_done(breq->mp, breq->startino))
return 0;
bcount = min(left, (int)(PAGE_SIZE / sizeof(*buffer)));
buffer = kmem_zalloc(bcount * sizeof(*buffer), KM_SLEEP);
do {
struct xfs_inobt_rec_incore r;
int stat;
error = xfs_inobt_walk(breq->mp, NULL, breq->startino,
xfs_inumbers_walk, breq->icount, &ic);
if (!agbp) {
error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
if (error)
break;
cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
XFS_BTNUM_INO);
error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE,
&stat);
if (error)
break;
if (!stat)
goto next_ag;
}
error = xfs_inobt_get_rec(cur, &r, &stat);
if (error)
break;
if (!stat)
goto next_ag;
agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1;
buffer[bufidx].xi_startino =
XFS_AGINO_TO_INO(mp, agno, r.ir_startino);
buffer[bufidx].xi_alloccount = r.ir_count - r.ir_freecount;
buffer[bufidx].xi_allocmask = ~r.ir_free;
if (++bufidx == bcount) {
long written;
error = formatter(ubuffer, buffer, bufidx, &written);
if (error)
break;
ubuffer += written;
*count += bufidx;
bufidx = 0;
}
if (!--left)
break;
error = xfs_btree_increment(cur, 0, &stat);
if (error)
break;
if (stat)
continue;
next_ag:
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
cur = NULL;
xfs_buf_relse(agbp);
agbp = NULL;
agino = 0;
agno++;
} while (agno < mp->m_sb.sb_agcount);
if (!error) {
if (bufidx) {
long written;
error = formatter(ubuffer, buffer, bufidx, &written);
if (!error)
*count += bufidx;
}
*lastino = XFS_AGINO_TO_INO(mp, agno, agino);
}
kmem_free(buffer);
if (cur)
xfs_btree_del_cursor(cur, error);
if (agbp)
xfs_buf_relse(agbp);
/*
* We found some inode groups, so clear the error status and return
* them. The lastino pointer will point directly at the inode that
* triggered any error that occurred, so on the next call the error
* will be triggered again and propagated to userspace as there will be
* no formatted inode groups in the buffer.
*/
if (breq->ocount > 0)
error = 0;
return error;
}

View File

@ -43,25 +43,9 @@ typedef int (*bulkstat_one_fmt_pf)(struct xfs_ibulk *breq,
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 */
const xfs_inogrp_t *buffer, /* buffer to read from */
long count, /* # of elements to read */
long *written); /* # of bytes written */
typedef int (*inumbers_fmt_pf)(struct xfs_ibulk *breq,
const struct xfs_inogrp *igrp);
int
xfs_inumbers_fmt(
void __user *ubuffer, /* buffer to write to */
const xfs_inogrp_t *buffer, /* buffer to read from */
long count, /* # of elements to read */
long *written); /* # of bytes written */
int /* error status */
xfs_inumbers(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t *last, /* last inode returned */
int *count, /* size of buffer/count returned */
void __user *buffer, /* buffer with inode info */
inumbers_fmt_pf formatter);
int xfs_inumbers(struct xfs_ibulk *breq, inumbers_fmt_pf formatter);
#endif /* __XFS_ITABLE_H__ */