/*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
-#include "xfs_dir.h"
#include "xfs_dir2.h"
#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
#include "xfs_dir2_sf.h"
#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_rw.h"
#include "xfs_inode_item.h"
#include "xfs_trans_space.h"
+#include "xfs_utils.h"
+#include "xfs_trace.h"
/*
*/
/*
- * xfs_lowbit32: get low bit set out of 32-bit argument, -1 if none set.
- */
-STATIC int
-xfs_lowbit32(
- __uint32_t v)
-{
- if (v)
- return ffs(v) - 1;
- return -1;
-}
-
-/*
* Allocate space to the bitmap or summary file, and zero it, for growfs.
*/
STATIC int /* error */
{
xfs_fileoff_t bno; /* block number in file */
xfs_buf_t *bp; /* temporary buffer for zeroing */
- int cancelflags; /* flags for xfs_trans_cancel */
int committed; /* transaction committed flag */
xfs_daddr_t d; /* disk block address */
int error; /* error return value */
xfs_bmbt_irec_t map; /* block map output */
int nmap; /* number of block maps */
int resblks; /* space reservation */
- xfs_trans_t *tp; /* transaction pointer */
/*
* Allocate space to the file, as necessary.
*/
while (oblocks < nblocks) {
+ int cancelflags = 0;
+ xfs_trans_t *tp;
+
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ALLOC);
resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks);
- cancelflags = 0;
/*
* Reserve space & log for one extent added to the file.
*/
XFS_GROWRTALLOC_LOG_RES(mp), 0,
XFS_TRANS_PERM_LOG_RES,
XFS_DEFAULT_PERM_LOG_COUNT)))
- goto error_exit;
+ goto error_cancel;
cancelflags = XFS_TRANS_RELEASE_LOG_RES;
/*
* Lock the inode.
*/
- if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, &ip)))
- goto error_exit;
- XFS_BMAP_INIT(&flist, &firstblock);
+ if ((error = xfs_trans_iget(mp, tp, ino, 0,
+ XFS_ILOCK_EXCL, &ip)))
+ goto error_cancel;
+ xfs_bmap_init(&flist, &firstblock);
/*
* Allocate blocks to the bitmap file.
*/
cancelflags |= XFS_TRANS_ABORT;
error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks,
XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock,
- resblks, &map, &nmap, &flist);
+ resblks, &map, &nmap, &flist, NULL);
if (!error && nmap < 1)
error = XFS_ERROR(ENOSPC);
if (error)
- goto error_exit;
+ goto error_cancel;
/*
* Free any blocks freed up in the transaction, then commit.
*/
- error = xfs_bmap_finish(&tp, &flist, firstblock, &committed);
+ error = xfs_bmap_finish(&tp, &flist, &committed);
+ if (error)
+ goto error_cancel;
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
- goto error_exit;
- xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ goto error;
/*
* Now we need to clear the allocated blocks.
* Do this one block per transaction, to keep it simple.
*/
if ((error = xfs_trans_reserve(tp, 0,
XFS_GROWRTZERO_LOG_RES(mp), 0, 0, 0)))
- goto error_exit;
+ goto error_cancel;
/*
* Lock the bitmap inode.
*/
- if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL,
- &ip)))
- goto error_exit;
+ if ((error = xfs_trans_iget(mp, tp, ino, 0,
+ XFS_ILOCK_EXCL, &ip)))
+ goto error_cancel;
/*
* Get a buffer for the block.
*/
mp->m_bsize, 0);
if (bp == NULL) {
error = XFS_ERROR(EIO);
- goto error_exit;
+error_cancel:
+ xfs_trans_cancel(tp, cancelflags);
+ goto error;
}
memset(XFS_BUF_PTR(bp), 0, mp->m_sb.sb_blocksize);
xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
/*
* Commit the transaction.
*/
- xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
+ if (error)
+ goto error;
}
/*
* Go on to the next extent, if any.
oblocks = map.br_startoff + map.br_blockcount;
}
return 0;
-error_exit:
- xfs_trans_cancel(tp, cancelflags);
+error:
return error;
}
}
bbno = XFS_BITTOBLOCK(mp, bno);
i = 0;
+ ASSERT(minlen != 0);
log2len = xfs_highbit32(minlen);
/*
* Loop over all bitmap blocks (bbno + i is current block).
xfs_suminfo_t sum; /* summary information for extents */
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
+ ASSERT(maxlen != 0);
+
/*
* Loop over all the levels starting with maxlen.
* At each level, look at all the bitmap blocks, to see if there
*rtblock = NULLRTBLOCK;
return 0;
}
+ ASSERT(minlen != 0);
+ ASSERT(maxlen != 0);
+
/*
* Loop over sizes, from maxlen down to minlen.
* This time, when we do the allocations, allow smaller ones
}
#endif
-#ifdef DEBUG
-/*
- * Check whether the given block in the bitmap has the given value.
- */
-STATIC int /* 1 for matches, 0 for not */
-xfs_rtcheck_bit(
- xfs_mount_t *mp, /* file system mount structure */
- xfs_trans_t *tp, /* transaction pointer */
- xfs_rtblock_t start, /* bit (block) to check */
- int val) /* 1 for free, 0 for allocated */
-{
- int bit; /* bit number in the word */
- xfs_rtblock_t block; /* bitmap block number */
- xfs_buf_t *bp; /* buf for the block */
- xfs_rtword_t *bufp; /* pointer into the buffer */
- /* REFERENCED */
- int error; /* error value */
- xfs_rtword_t wdiff; /* difference between bit & expected */
- int word; /* word number in the buffer */
- xfs_rtword_t wval; /* word value from buffer */
-
- block = XFS_BITTOBLOCK(mp, start);
- error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
- bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
- word = XFS_BITTOWORD(mp, start);
- bit = (int)(start & (XFS_NBWORD - 1));
- wval = bufp[word];
- xfs_trans_brelse(tp, bp);
- wdiff = (wval ^ -val) & ((xfs_rtword_t)1 << bit);
- return !wdiff;
-}
-#endif /* DEBUG */
-
-#if 0
-/*
- * Check that the given extent (block range) is free already.
- */
-STATIC int /* error */
-xfs_rtcheck_free_range(
- xfs_mount_t *mp, /* file system mount point */
- xfs_trans_t *tp, /* transaction pointer */
- xfs_rtblock_t bno, /* starting block number of extent */
- xfs_extlen_t len, /* length of extent */
- int *stat) /* out: 1 for free, 0 for not */
-{
- xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */
-
- return xfs_rtcheck_range(mp, tp, bno, len, 1, &new, stat);
-}
-#endif
-
/*
* Check that the given range is either all allocated (val = 0) or
* all free (val = 1).
{
xfs_rtblock_t bmbno; /* bitmap block number */
xfs_buf_t *bp; /* temporary buffer */
- int cancelflags; /* flags for xfs_trans_cancel */
int error; /* error return value */
xfs_inode_t *ip; /* bitmap inode, used as lock */
xfs_mount_t *nmp; /* new (fake) mount structure */
xfs_extlen_t rsumblocks; /* current number of rt summary blks */
xfs_sb_t *sbp; /* old superblock */
xfs_fsblock_t sumbno; /* summary block number */
- xfs_trans_t *tp; /* transaction pointer */
sbp = &mp->m_sb;
/*
* Initial error checking.
*/
- if (mp->m_rtdev_targp || mp->m_rbmip == NULL ||
+ if (!capable(CAP_SYS_ADMIN))
+ return XFS_ERROR(EPERM);
+ if (mp->m_rtdev_targp == NULL || mp->m_rbmip == NULL ||
(nrblocks = in->newblocks) <= sbp->sb_rblocks ||
(sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize)))
return XFS_ERROR(EINVAL);
+ if ((error = xfs_sb_validate_fsb_count(sbp, nrblocks)))
+ return error;
/*
* Read in the last block of the device, make sure it exists.
*/
error = xfs_read_buf(mp, mp->m_rtdev_targp,
- XFS_FSB_TO_BB(mp, in->newblocks - 1),
+ XFS_FSB_TO_BB(mp, nrblocks - 1),
XFS_FSB_TO_BB(mp, 1), 0, &bp);
if (error)
return error;
*/
nrextents = nrblocks;
do_div(nrextents, in->extsize);
- nrbmblocks = roundup_64(nrextents, NBBY * sbp->sb_blocksize);
+ nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize);
nrextslog = xfs_highbit32(nrextents);
nrsumlevels = nrextslog + 1;
nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks;
if ((error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks,
mp->m_sb.sb_rsumino)))
return error;
- nmp = NULL;
+ /*
+ * Allocate a new (fake) mount/sb.
+ */
+ nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP);
/*
* Loop over the bitmap blocks.
* We will do everything one bitmap block at a time.
((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);
bmbno < nrbmblocks;
bmbno++) {
- /*
- * Allocate a new (fake) mount/sb.
- */
- nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP);
+ xfs_trans_t *tp;
+ int cancelflags = 0;
+
*nmp = *mp;
nsbp = &nmp->m_sb;
/*
nsbp->sb_blocksize * nsbp->sb_rextsize);
nsbp->sb_rextents = nsbp->sb_rblocks;
do_div(nsbp->sb_rextents, nsbp->sb_rextsize);
+ ASSERT(nsbp->sb_rextents != 0);
nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents);
nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1;
nrsumsize =
* Start a transaction, get the log reservation.
*/
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_FREE);
- cancelflags = 0;
if ((error = xfs_trans_reserve(tp, 0,
XFS_GROWRTFREE_LOG_RES(nmp), 0, 0, 0)))
- goto error_exit;
+ goto error_cancel;
/*
* Lock out other callers by grabbing the bitmap inode lock.
*/
- if ((error = xfs_trans_iget(mp, tp, 0, mp->m_sb.sb_rbmino,
- XFS_ILOCK_EXCL, &ip)))
- goto error_exit;
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
+ XFS_ILOCK_EXCL, &ip)))
+ goto error_cancel;
ASSERT(ip == mp->m_rbmip);
/*
* Update the bitmap inode's size.
/*
* Get the summary inode into the transaction.
*/
- if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino,
- 0, XFS_ILOCK_EXCL, &ip)))
- goto error_exit;
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0,
+ XFS_ILOCK_EXCL, &ip)))
+ goto error_cancel;
ASSERT(ip == mp->m_rsumip);
/*
* Update the summary inode's size.
mp->m_rsumlevels != nmp->m_rsumlevels) {
error = xfs_rtcopy_summary(mp, nmp, tp);
if (error)
- goto error_exit;
+ goto error_cancel;
}
/*
* Update superblock fields.
bp = NULL;
error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
- if (error)
- goto error_exit;
+ if (error) {
+error_cancel:
+ xfs_trans_cancel(tp, cancelflags);
+ break;
+ }
/*
* Mark more blocks free in the superblock.
*/
xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS,
nsbp->sb_rextents - sbp->sb_rextents);
/*
- * Free the fake mp structure.
- */
- kmem_free(nmp, sizeof(*nmp));
- nmp = NULL;
- /*
* Update mp values into the real mp structure.
*/
mp->m_rsumlevels = nrsumlevels;
mp->m_rsumsize = nrsumsize;
- /*
- * Commit the transaction.
- */
- xfs_trans_commit(tp, 0, NULL);
+
+ error = xfs_trans_commit(tp, 0);
+ if (error)
+ break;
}
- return 0;
/*
- * Error paths come here.
+ * Free the fake mp structure.
*/
-error_exit:
- if (nmp)
- kmem_free(nmp, sizeof(*nmp));
- xfs_trans_cancel(tp, cancelflags);
+ kmem_free(nmp);
+
return error;
}
/*
* Lock out other callers by grabbing the bitmap inode lock.
*/
- error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip);
- if (error) {
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
+ XFS_ILOCK_EXCL, &ip)))
return error;
- }
sumbp = NULL;
/*
* Allocate by size, or near another block, or exactly at some block.
/*
* Synchronize by locking the bitmap inode.
*/
- error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip);
- if (error) {
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
+ XFS_ILOCK_EXCL, &ip)))
return error;
- }
#if defined(__KERNEL__) && defined(DEBUG)
/*
* Check to see that this whole range is currently allocated.
ASSERT(sbp->sb_rsumino != NULLFSINO);
error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip, 0);
if (error) {
- VN_RELE(XFS_ITOV(mp->m_rbmip));
+ IRELE(mp->m_rbmip);
return error;
}
ASSERT(mp->m_rsumip != NULL);
return 0;
}
+void
+xfs_rtunmount_inodes(
+ struct xfs_mount *mp)
+{
+ if (mp->m_rbmip)
+ IRELE(mp->m_rbmip);
+ if (mp->m_rsumip)
+ IRELE(mp->m_rsumip);
+}
+
/*
* Pick an extent for allocation at the start of a new realtime file.
* Use the sequence number stored in the atime field of the bitmap inode.
__uint64_t seq; /* sequence number of file creation */
__uint64_t *seqp; /* pointer to seqno in inode */
- error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip);
- if (error)
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
+ XFS_ILOCK_EXCL, &ip)))
return error;
ASSERT(ip == mp->m_rbmip);
seqp = (__uint64_t *)&ip->i_d.di_atime;
*pick = b;
return 0;
}
-
-#ifdef DEBUG
-/*
- * Debug code: print out the value of a range in the bitmap.
- */
-void
-xfs_rtprint_range(
- xfs_mount_t *mp, /* file system mount structure */
- xfs_trans_t *tp, /* transaction pointer */
- xfs_rtblock_t start, /* starting block to print */
- xfs_extlen_t len) /* length to print */
-{
- xfs_extlen_t i; /* block number in the extent */
-
- printk("%Ld: ", (long long)start);
- for (i = 0; i < len; i++)
- printk("%d", xfs_rtcheck_bit(mp, tp, start + i, 1));
- printk("\n");
-}
-
-/*
- * Debug code: print the summary file.
- */
-void
-xfs_rtprint_summary(
- xfs_mount_t *mp, /* file system mount structure */
- xfs_trans_t *tp) /* transaction pointer */
-{
- xfs_suminfo_t c; /* summary data */
- xfs_rtblock_t i; /* bitmap block number */
- int l; /* summary information level */
- int p; /* flag for printed anything */
- xfs_fsblock_t sb; /* summary block number */
- xfs_buf_t *sumbp; /* summary block buffer */
-
- sumbp = NULL;
- for (l = 0; l < mp->m_rsumlevels; l++) {
- for (p = 0, i = 0; i < mp->m_sb.sb_rbmblocks; i++) {
- (void)xfs_rtget_summary(mp, tp, l, i, &sumbp, &sb, &c);
- if (c) {
- if (!p) {
- printk("%Ld-%Ld:", 1LL << l,
- XFS_RTMIN((1LL << l) +
- ((1LL << l) - 1LL),
- mp->m_sb.sb_rextents));
- p = 1;
- }
- printk(" %Ld:%d", (long long)i, c);
- }
- }
- if (p)
- printk("\n");
- }
- if (sumbp)
- xfs_trans_brelse(tp, sumbp);
-}
-#endif /* DEBUG */