Merge tag 'libnvdimm-for-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm...
[linux-block.git] / fs / jfs / jfs_dmap.c
index 88afd108c2dd2e04c63ee2bb7348c8173bc6d26b..11c77757ead9e00b684da592de0b2232034ebda1 100644 (file)
@@ -87,7 +87,7 @@ static int dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno,
 static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks);
 static int dbFindBits(u32 word, int l2nb);
 static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno);
-static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx);
+static int dbFindLeaf(dmtree_t *tp, int l2nb, int *leafidx, bool is_ctl);
 static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
                      int nblocks);
 static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
@@ -180,7 +180,8 @@ int dbMount(struct inode *ipbmap)
        bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree);
 
        bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage);
-       if (bmp->db_l2nbperpage > L2PSIZE - L2MINBLOCKSIZE) {
+       if (bmp->db_l2nbperpage > L2PSIZE - L2MINBLOCKSIZE ||
+               bmp->db_l2nbperpage < 0) {
                err = -EINVAL;
                goto err_release_metapage;
        }
@@ -194,6 +195,12 @@ int dbMount(struct inode *ipbmap)
        bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel);
        bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag);
        bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref);
+       if (bmp->db_maxag >= MAXAG || bmp->db_maxag < 0 ||
+               bmp->db_agpref >= MAXAG || bmp->db_agpref < 0) {
+               err = -EINVAL;
+               goto err_release_metapage;
+       }
+
        bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel);
        bmp->db_agheight = le32_to_cpu(dbmp_le->dn_agheight);
        bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
@@ -1710,7 +1717,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
                 * dbFindLeaf() returns the index of the leaf at which
                 * free space was found.
                 */
-               rc = dbFindLeaf((dmtree_t *) dcp, l2nb, &leafidx);
+               rc = dbFindLeaf((dmtree_t *) dcp, l2nb, &leafidx, true);
 
                /* release the buffer.
                 */
@@ -1957,7 +1964,7 @@ dbAllocDmapLev(struct bmap * bmp,
         * free space.  if sufficient free space is found, dbFindLeaf()
         * returns the index of the leaf at which free space was found.
         */
-       if (dbFindLeaf((dmtree_t *) & dp->tree, l2nb, &leafidx))
+       if (dbFindLeaf((dmtree_t *) &dp->tree, l2nb, &leafidx, false))
                return -ENOSPC;
 
        if (leafidx < 0)
@@ -2921,14 +2928,18 @@ static void dbAdjTree(dmtree_t * tp, int leafno, int newval)
  *     leafidx - return pointer to be set to the index of the leaf
  *               describing at least l2nb free blocks if sufficient
  *               free blocks are found.
+ *     is_ctl  - determines if the tree is of type ctl
  *
  * RETURN VALUES:
  *     0       - success
  *     -ENOSPC - insufficient free blocks.
  */
-static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
+static int dbFindLeaf(dmtree_t *tp, int l2nb, int *leafidx, bool is_ctl)
 {
        int ti, n = 0, k, x = 0;
+       int max_size;
+
+       max_size = is_ctl ? CTLTREESIZE : TREESIZE;
 
        /* first check the root of the tree to see if there is
         * sufficient free space.
@@ -2949,6 +2960,8 @@ static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
                        /* sufficient free space found.  move to the next
                         * level (or quit if this is the last level).
                         */
+                       if (x + n > max_size)
+                               return -ENOSPC;
                        if (l2nb <= tp->dmt_stree[x + n])
                                break;
                }