xfs_ino_t ino)
{
return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
- (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
+ (xfs_sb_version_hasquota(&mp->m_sb) &&
(ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));
}
return error;
}
-STATIC int
+STATIC void
xfs_bulkstat_one_dinode(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t ino, /* inode number to get data for */
buf->bs_mtime.tv_nsec = be32_to_cpu(dic->di_mtime.t_nsec);
buf->bs_ctime.tv_sec = be32_to_cpu(dic->di_ctime.t_sec);
buf->bs_ctime.tv_nsec = be32_to_cpu(dic->di_ctime.t_nsec);
- buf->bs_xflags = xfs_dic2xflags(dic);
+ buf->bs_xflags = xfs_dic2xflags(dip);
buf->bs_extsize = be32_to_cpu(dic->di_extsize) << mp->m_sb.sb_blocklog;
buf->bs_extents = be32_to_cpu(dic->di_nextents);
buf->bs_gen = be32_to_cpu(dic->di_gen);
buf->bs_blocks = be64_to_cpu(dic->di_nblocks);
break;
}
-
- return 0;
}
STATIC int
return 1;
dip = (xfs_dinode_t *)
xfs_buf_offset(bp, clustidx << mp->m_sb.sb_inodelog);
+ /*
+ * Check the buffer containing the on-disk inode for di_mode == 0.
+ * This is to prevent xfs_bulkstat from picking up just reclaimed
+ * inodes that have their in-core state initialized but not flushed
+ * to disk yet. This is a temporary hack that would require a proper
+ * fix in the future.
+ */
if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC ||
- !XFS_DINODE_GOOD_VERSION(dip->di_core.di_version))
+ !XFS_DINODE_GOOD_VERSION(dip->di_core.di_version) ||
+ !dip->di_core.di_mode)
return 0;
if (flags & BULKSTAT_FG_QUICK) {
*dipp = dip;
}
/* BULKSTAT_FG_INLINE: if attr fork is local, or not there, use it */
aformat = dip->di_core.di_aformat;
- if ((XFS_CFORK_Q(&dip->di_core) == 0) ||
+ if ((XFS_DFORK_Q(dip) == 0) ||
(aformat == XFS_DINODE_FMT_LOCAL) ||
(aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_core.di_anextents)) {
*dipp = dip;
return 1;
}
+#define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size)
+
/*
* Return stat information in bulk (by-inode) for the filesystem.
*/
xfs_inobt_rec_incore_t *irbp; /* current irec buffer pointer */
xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */
xfs_inobt_rec_incore_t *irbufend; /* end of good irec buffer entries */
- xfs_ino_t lastino=0; /* last inode number returned */
+ xfs_ino_t lastino; /* last inode number returned */
int nbcluster; /* # of blocks in a cluster */
int nicluster; /* # of inodes in a cluster */
int nimask; /* mask for inode clusters */
* Get the last inode value, see if there's nothing to do.
*/
ino = (xfs_ino_t)*lastinop;
+ lastino = ino;
dip = NULL;
agno = XFS_INO_TO_AGNO(mp, ino);
agino = XFS_INO_TO_AGINO(mp, ino);
*ubcountp = 0;
return 0;
}
+ if (!ubcountp || *ubcountp <= 0) {
+ return EINVAL;
+ }
ubcount = *ubcountp; /* statstruct's */
ubleft = ubcount * statstruct_size; /* bytes */
*ubcountp = ubelem = 0;
(XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog);
nimask = ~(nicluster - 1);
nbcluster = nicluster >> mp->m_sb.sb_inopblog;
- irbuf = kmem_zalloc_greedy(&irbsize, NBPC, NBPC * 4,
+ irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4,
KM_SLEEP | KM_MAYFAIL | KM_LARGE);
nirbuf = irbsize / sizeof(*irbuf);
* inode returned; 0 means start of the allocation group.
*/
rval = 0;
- while (ubleft >= statstruct_size && agno < mp->m_sb.sb_agcount) {
+ while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {
+ cond_resched();
bp = NULL;
down_read(&mp->m_peraglock);
error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
break;
error = xfs_inobt_lookup_ge(cur, agino, 0, 0,
&tmp);
+ cond_resched();
}
/*
* If ran off the end of the ag either with an error,
*/
agino = gino + XFS_INODES_PER_CHUNK;
error = xfs_inobt_increment(cur, 0, &tmp);
+ cond_resched();
}
/*
* Drop the btree buffers and the agi buffer.
*/
irbufend = irbp;
for (irbp = irbuf;
- irbp < irbufend && ubleft >= statstruct_size; irbp++) {
+ irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft); irbp++) {
/*
* Now process this chunk of inodes.
*/
for (agino = irbp->ir_startino, chunkidx = clustidx = 0;
- ubleft > 0 &&
+ XFS_BULKSTAT_UBLEFT(ubleft) &&
irbp->ir_freecount < XFS_INODES_PER_CHUNK;
chunkidx++, clustidx++, agino++) {
ASSERT(chunkidx < XFS_INODES_PER_CHUNK);
xfs_buf_relse(bp);
error = xfs_itobp(mp, NULL, ip,
&dip, &bp, bno,
- XFS_IMAP_BULKSTAT);
+ XFS_IMAP_BULKSTAT,
+ XFS_BUF_LOCK);
if (!error)
clustidx = ip->i_boffset / mp->m_sb.sb_inodesize;
kmem_zone_free(xfs_inode_zone, ip);
}
}
}
+ ino = XFS_AGINO_TO_INO(mp, agno, agino);
+ bno = XFS_AGB_TO_DADDR(mp, agno, agbno);
/*
* Skip if this inode is free.
*/
- if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free)
+ if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) {
+ lastino = ino;
continue;
+ }
/*
* Count used inodes as free so we can tell
* when the chunk is used up.
*/
irbp->ir_freecount++;
- ino = XFS_AGINO_TO_INO(mp, agno, agino);
- bno = XFS_AGB_TO_DADDR(mp, agno, agbno);
if (!xfs_bulkstat_use_dinode(mp, flags, bp,
- clustidx, &dip))
+ clustidx, &dip)) {
+ lastino = ino;
continue;
+ }
/*
* If we need to do an iget, cannot hold bp.
* Drop it, until starting the next cluster.
ubleft, private_data,
bno, &ubused, dip, &fmterror);
if (fmterror == BULKSTAT_RV_NOTHING) {
- if (error == EFAULT) {
- ubleft = 0;
- rval = error;
- break;
- }
- else if (error == ENOMEM)
+ if (error && error != ENOENT &&
+ error != EINVAL) {
ubleft = 0;
- else
- lastino = ino;
+ rval = error;
+ break;
+ }
+ lastino = ino;
continue;
}
if (fmterror == BULKSTAT_RV_GIVEUP) {
ubelem++;
lastino = ino;
}
+
+ cond_resched();
}
if (bp)
/*
* Set up for the next loop iteration.
*/
- if (ubleft > 0) {
+ if (XFS_BULKSTAT_UBLEFT(ubleft)) {
if (end_of_ag) {
agno++;
agino = 0;
*/
kmem_free(irbuf, irbsize);
*ubcountp = ubelem;
+ /*
+ * Found some inodes, return them now and return the error next time.
+ */
+ if (ubelem)
+ rval = 0;
if (agno >= mp->m_sb.sb_agcount) {
/*
* If we ran out of filesystem, mark lastino as off
agino = XFS_INO_TO_AGINO(mp, ino);
left = *count;
*count = 0;
- bcount = MIN(left, (int)(NBPP / sizeof(*buffer)));
+ bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer)));
buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP);
error = bufidx = 0;
cur = NULL;