summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2014-09-09 13:25:31 +1000
committerDave Chinner <david@fromorbit.com>2014-09-09 13:25:31 +1000
commita4241aebe924136d6838fd516da6daa727fcd728 (patch)
tree5a69b8c8e2ab358ad490150c2bd5b0c53893b5e7 /fs/xfs/libxfs
parent41b9d7263ea1e270019c5d04fa0ab15db50b9725 (diff)
parentab6978c295b074eb2ba4b06fdf206c7ab4f293e5 (diff)
Merge branch 'xfs-misc-fixes-for-3.18-1' into for-next
Diffstat (limited to 'fs/xfs/libxfs')
-rw-r--r--fs/xfs/libxfs/xfs_alloc.c4
-rw-r--r--fs/xfs/libxfs/xfs_dir2.c67
-rw-r--r--fs/xfs/libxfs/xfs_dir2.h2
-rw-r--r--fs/xfs/libxfs/xfs_ialloc.c2
-rw-r--r--fs/xfs/libxfs/xfs_rtbitmap.c49
-rw-r--r--fs/xfs/libxfs/xfs_sb.c2
6 files changed, 56 insertions, 70 deletions
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 4bffffe038a1..eff34218f405 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -2209,6 +2209,10 @@ xfs_agf_verify(
be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
return false;
+ if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
+ be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
+ return false;
+
/*
* during growfs operations, the perag is not fully initialised,
* so we can't use it for any useful checking. growfs ensures we can't
diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index 6cef22152fd6..7075aaf131f4 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -237,7 +237,8 @@ xfs_dir_init(
}
/*
- Enter a name in a directory.
+ * Enter a name in a directory, or check for available space.
+ * If inum is 0, only the available space test is performed.
*/
int
xfs_dir_createname(
@@ -254,10 +255,12 @@ xfs_dir_createname(
int v; /* type-checking value */
ASSERT(S_ISDIR(dp->i_d.di_mode));
- rval = xfs_dir_ino_validate(tp->t_mountp, inum);
- if (rval)
- return rval;
- XFS_STATS_INC(xs_dir_create);
+ if (inum) {
+ rval = xfs_dir_ino_validate(tp->t_mountp, inum);
+ if (rval)
+ return rval;
+ XFS_STATS_INC(xs_dir_create);
+ }
args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
if (!args)
@@ -276,6 +279,8 @@ xfs_dir_createname(
args->whichfork = XFS_DATA_FORK;
args->trans = tp;
args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
+ if (!inum)
+ args->op_flags |= XFS_DA_OP_JUSTCHECK;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
rval = xfs_dir2_sf_addname(args);
@@ -535,62 +540,14 @@ out_free:
/*
* See if this entry can be added to the directory without allocating space.
- * First checks that the caller couldn't reserve enough space (resblks = 0).
*/
int
xfs_dir_canenter(
xfs_trans_t *tp,
xfs_inode_t *dp,
- struct xfs_name *name, /* name of entry to add */
- uint resblks)
+ struct xfs_name *name) /* name of entry to add */
{
- struct xfs_da_args *args;
- int rval;
- int v; /* type-checking value */
-
- if (resblks)
- return 0;
-
- ASSERT(S_ISDIR(dp->i_d.di_mode));
-
- args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
- if (!args)
- return -ENOMEM;
-
- args->geo = dp->i_mount->m_dir_geo;
- args->name = name->name;
- args->namelen = name->len;
- args->filetype = name->type;
- args->hashval = dp->i_mount->m_dirnameops->hashname(name);
- args->dp = dp;
- args->whichfork = XFS_DATA_FORK;
- args->trans = tp;
- args->op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME |
- XFS_DA_OP_OKNOENT;
-
- if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
- rval = xfs_dir2_sf_addname(args);
- goto out_free;
- }
-
- rval = xfs_dir2_isblock(args, &v);
- if (rval)
- goto out_free;
- if (v) {
- rval = xfs_dir2_block_addname(args);
- goto out_free;
- }
-
- rval = xfs_dir2_isleaf(args, &v);
- if (rval)
- goto out_free;
- if (v)
- rval = xfs_dir2_leaf_addname(args);
- else
- rval = xfs_dir2_node_addname(args);
-out_free:
- kmem_free(args);
- return rval;
+ return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0);
}
/*
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index c8e86b0b5e99..4dff261e6ed5 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/libxfs/xfs_dir2.h
@@ -136,7 +136,7 @@ extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_fsblock_t *first,
struct xfs_bmap_free *flist, xfs_extlen_t tot);
extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
- struct xfs_name *name, uint resblks);
+ struct xfs_name *name);
/*
* Direct call from the bmap code, bypassing the generic directory layer.
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index b62771f1f4b5..d213a2eae95e 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2051,6 +2051,8 @@ xfs_agi_verify(
if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
return false;
+ if (be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS)
+ return false;
/*
* during growfs operations, the perag is not fully initialised,
* so we can't use it for any useful checking. growfs ensures we can't
diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c
index f4dd697cac08..7c818f1e4484 100644
--- a/fs/xfs/libxfs/xfs_rtbitmap.c
+++ b/fs/xfs/libxfs/xfs_rtbitmap.c
@@ -424,20 +424,24 @@ xfs_rtfind_forw(
}
/*
- * Read and modify the summary information for a given extent size,
+ * Read and/or modify the summary information for a given extent size,
* bitmap block combination.
* Keeps track of a current summary block, so we don't keep reading
* it from the buffer cache.
+ *
+ * Summary information is returned in *sum if specified.
+ * If no delta is specified, returns summary only.
*/
int
-xfs_rtmodify_summary(
- xfs_mount_t *mp, /* file system mount point */
+xfs_rtmodify_summary_int(
+ xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
int log, /* log2 of extent size */
xfs_rtblock_t bbno, /* bitmap block number */
int delta, /* change to make to summary info */
xfs_buf_t **rbpp, /* in/out: summary block buffer */
- xfs_fsblock_t *rsb) /* in/out: summary block number */
+ xfs_fsblock_t *rsb, /* in/out: summary block number */
+ xfs_suminfo_t *sum) /* out: summary info for this block */
{
xfs_buf_t *bp; /* buffer for the summary block */
int error; /* error value */
@@ -456,7 +460,7 @@ xfs_rtmodify_summary(
/*
* If we have an old buffer, and the block number matches, use that.
*/
- if (rbpp && *rbpp && *rsb == sb)
+ if (*rbpp && *rsb == sb)
bp = *rbpp;
/*
* Otherwise we have to get the buffer.
@@ -465,7 +469,7 @@ xfs_rtmodify_summary(
/*
* If there was an old one, get rid of it first.
*/
- if (rbpp && *rbpp)
+ if (*rbpp)
xfs_trans_brelse(tp, *rbpp);
error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
if (error) {
@@ -474,21 +478,38 @@ xfs_rtmodify_summary(
/*
* Remember this buffer and block for the next call.
*/
- if (rbpp) {
- *rbpp = bp;
- *rsb = sb;
- }
+ *rbpp = bp;
+ *rsb = sb;
}
/*
- * Point to the summary information, modify and log it.
+ * Point to the summary information, modify/log it, and/or copy it out.
*/
sp = XFS_SUMPTR(mp, bp, so);
- *sp += delta;
- xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)bp->b_addr),
- (uint)((char *)sp - (char *)bp->b_addr + sizeof(*sp) - 1));
+ if (delta) {
+ uint first = (uint)((char *)sp - (char *)bp->b_addr);
+
+ *sp += delta;
+ xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1);
+ }
+ if (sum)
+ *sum = *sp;
return 0;
}
+int
+xfs_rtmodify_summary(
+ xfs_mount_t *mp, /* file system mount structure */
+ xfs_trans_t *tp, /* transaction pointer */
+ int log, /* log2 of extent size */
+ xfs_rtblock_t bbno, /* bitmap block number */
+ int delta, /* change to make to summary info */
+ xfs_buf_t **rbpp, /* in/out: summary block buffer */
+ xfs_fsblock_t *rsb) /* in/out: summary block number */
+{
+ return xfs_rtmodify_summary_int(mp, tp, log, bbno,
+ delta, rbpp, rsb, NULL);
+}
+
/*
* Set the given range of bitmap bits to the given value.
* Do whatever I/O and logging is required.
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index ad525a5623a4..8426e5e2682e 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -279,11 +279,13 @@ xfs_mount_validate_sb(
sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG ||
sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG ||
sbp->sb_blocksize != (1 << sbp->sb_blocklog) ||
+ sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG ||
sbp->sb_inodesize < XFS_DINODE_MIN_SIZE ||
sbp->sb_inodesize > XFS_DINODE_MAX_SIZE ||
sbp->sb_inodelog < XFS_DINODE_MIN_LOG ||
sbp->sb_inodelog > XFS_DINODE_MAX_LOG ||
sbp->sb_inodesize != (1 << sbp->sb_inodelog) ||
+ sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE ||
sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) ||
(sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) ||
(sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) ||