diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 78312b0c7b34f937618d1d302739fcb2adad8f61..a3e551bb906b514d7b7aaf18c06f4a534a327f01 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -84,10 +84,9 @@ xfs_bulkstat_one( xfs_arch_t arch; /* these are set according to */ __uint16_t di_flags; /* temp */ - buf = (xfs_bstat_t *)buffer; dip = (xfs_dinode_t *)dibuff; - if (! buf || ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || + if (!buffer || ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino))) { *stat = BULKSTAT_RV_NOTHING; @@ -98,6 +97,8 @@ xfs_bulkstat_one( return XFS_ERROR(ENOMEM); } + buf = kmem_alloc(sizeof(*buf), KM_SLEEP); + if (dip == NULL) { /* We're not being passed a pointer to a dinode. This happens * if BULKSTAT_FG_IGET is selected. Do the iget. @@ -112,6 +113,7 @@ xfs_bulkstat_one( if (ip->i_d.di_mode == 0) { xfs_iput_new(ip, XFS_ILOCK_SHARED); *stat = BULKSTAT_RV_NOTHING; + kmem_free(buf, sizeof(*buf)); return XFS_ERROR(ENOENT); } dic = &ip->i_d; @@ -228,6 +230,13 @@ xfs_bulkstat_one( xfs_iput(ip, XFS_ILOCK_SHARED); } + if (copy_to_user(buffer, buf, sizeof(*buf))) { + kmem_free(buf, sizeof(*buf)); + *stat = BULKSTAT_RV_NOTHING; + return EFAULT; + } + + kmem_free(buf, sizeof(*buf)); *stat = BULKSTAT_RV_DIDONE; if (ubused) *ubused = sizeof(*buf); @@ -650,7 +659,6 @@ xfs_bulkstat_single( xfs_caddr_t buffer, /* buffer with inode stats */ int *done) /* 1 if there're more stats to get */ { - xfs_bstat_t bstat; /* one bulkstat result structure */ int count; /* count value for bulkstat call */ int error; /* return value */ xfs_ino_t ino; /* filesystem inode number */ @@ -666,7 +674,7 @@ xfs_bulkstat_single( */ ino = (xfs_ino_t)*lastinop; - error = xfs_bulkstat_one(mp, ino, &bstat, sizeof(bstat), + error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t), NULL, 0, NULL, NULL, &res); if (error) { /* @@ -676,8 +684,8 @@ xfs_bulkstat_single( (*lastinop)--; count = 1; if (xfs_bulkstat(mp, lastinop, &count, xfs_bulkstat_one, - NULL, - sizeof(bstat), buffer, BULKSTAT_FG_IGET, done)) + NULL, sizeof(xfs_bstat_t), buffer, + BULKSTAT_FG_IGET, done)) return error; if (count == 0 || (xfs_ino_t)*lastinop != ino) return error == EFSCORRUPTED ? @@ -686,8 +694,6 @@ xfs_bulkstat_single( return 0; } *done = 0; - if (copy_to_user(buffer, &bstat, sizeof(bstat))) - return XFS_ERROR(EFAULT); return 0; }