diff options
Diffstat (limited to 'fs/jfs/jfs_dtree.c')
| -rw-r--r-- | fs/jfs/jfs_dtree.c | 360 |
1 files changed, 42 insertions, 318 deletions
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 52bae3f5c914..0ab83bb7bbdf 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -1,19 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) International Business Machines Corp., 2000-2004 - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* @@ -130,7 +117,8 @@ do { \ if (!(RC)) { \ if (((P)->header.nextindex > \ (((BN) == 0) ? DTROOTMAXSLOT : (P)->header.maxslot)) || \ - ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT))) { \ + ((BN) && (((P)->header.maxslot > DTPAGEMAXSLOT) || \ + ((P)->header.stblindex >= DTPAGEMAXSLOT)))) { \ BT_PUTPAGE(MP); \ jfs_error((IP)->i_sb, \ "DT_GETPAGE: dtree page corrupt\n"); \ @@ -646,6 +634,11 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, for (base = 0, lim = p->header.nextindex; lim; lim >>= 1) { index = base + (lim >> 1); + if (stbl[index] < 0) { + rc = -EIO; + goto out; + } + if (p->header.flag & BT_LEAF) { /* uppercase leaf name to compare */ cmp = @@ -842,6 +835,8 @@ int dtInsert(tid_t tid, struct inode *ip, * the full page. */ DT_GETSEARCH(ip, btstack->top, bn, mp, p, index); + if (p->header.freelist == 0) + return -EINVAL; /* * insert entry for new key @@ -1983,7 +1978,7 @@ static int dtSplitRoot(tid_t tid, do { f = &rp->slot[fsi]; fsi = f->next; - } while (fsi != -1); + } while (fsi >= 0); f->next = n; } @@ -2436,304 +2431,6 @@ static int dtDeleteUp(tid_t tid, struct inode *ip, return 0; } -#ifdef _NOTYET -/* - * NAME: dtRelocate() - * - * FUNCTION: relocate dtpage (internal or leaf) of directory; - * This function is mainly used by defragfs utility. - */ -int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd, - s64 nxaddr) -{ - int rc = 0; - struct metapage *mp, *pmp, *lmp, *rmp; - dtpage_t *p, *pp, *rp = 0, *lp= 0; - s64 bn; - int index; - struct btstack btstack; - pxd_t *pxd; - s64 oxaddr, nextbn, prevbn; - int xlen, xsize; - struct tlock *tlck; - struct dt_lock *dtlck; - struct pxd_lock *pxdlock; - s8 *stbl; - struct lv *lv; - - oxaddr = addressPXD(opxd); - xlen = lengthPXD(opxd); - - jfs_info("dtRelocate: lmxaddr:%Ld xaddr:%Ld:%Ld xlen:%d", - (long long)lmxaddr, (long long)oxaddr, (long long)nxaddr, - xlen); - - /* - * 1. get the internal parent dtpage covering - * router entry for the tartget page to be relocated; - */ - rc = dtSearchNode(ip, lmxaddr, opxd, &btstack); - if (rc) - return rc; - - /* retrieve search result */ - DT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); - jfs_info("dtRelocate: parent router entry validated."); - - /* - * 2. relocate the target dtpage - */ - /* read in the target page from src extent */ - DT_GETPAGE(ip, oxaddr, mp, PSIZE, p, rc); - if (rc) { - /* release the pinned parent page */ - DT_PUTPAGE(pmp); - return rc; - } - - /* - * read in sibling pages if any to update sibling pointers; - */ - rmp = NULL; - if (p->header.next) { - nextbn = le64_to_cpu(p->header.next); - DT_GETPAGE(ip, nextbn, rmp, PSIZE, rp, rc); - if (rc) { - DT_PUTPAGE(mp); - DT_PUTPAGE(pmp); - return (rc); - } - } - - lmp = NULL; - if (p->header.prev) { - prevbn = le64_to_cpu(p->header.prev); - DT_GETPAGE(ip, prevbn, lmp, PSIZE, lp, rc); - if (rc) { - DT_PUTPAGE(mp); - DT_PUTPAGE(pmp); - if (rmp) - DT_PUTPAGE(rmp); - return (rc); - } - } - - /* at this point, all xtpages to be updated are in memory */ - - /* - * update sibling pointers of sibling dtpages if any; - */ - if (lmp) { - tlck = txLock(tid, ip, lmp, tlckDTREE | tlckRELINK); - dtlck = (struct dt_lock *) & tlck->lock; - /* linelock header */ - ASSERT(dtlck->index == 0); - lv = & dtlck->lv[0]; - lv->offset = 0; - lv->length = 1; - dtlck->index++; - - lp->header.next = cpu_to_le64(nxaddr); - DT_PUTPAGE(lmp); - } - - if (rmp) { - tlck = txLock(tid, ip, rmp, tlckDTREE | tlckRELINK); - dtlck = (struct dt_lock *) & tlck->lock; - /* linelock header */ - ASSERT(dtlck->index == 0); - lv = & dtlck->lv[0]; - lv->offset = 0; - lv->length = 1; - dtlck->index++; - - rp->header.prev = cpu_to_le64(nxaddr); - DT_PUTPAGE(rmp); - } - - /* - * update the target dtpage to be relocated - * - * write LOG_REDOPAGE of LOG_NEW type for dst page - * for the whole target page (logredo() will apply - * after image and update bmap for allocation of the - * dst extent), and update bmap for allocation of - * the dst extent; - */ - tlck = txLock(tid, ip, mp, tlckDTREE | tlckNEW); - dtlck = (struct dt_lock *) & tlck->lock; - /* linelock header */ - ASSERT(dtlck->index == 0); - lv = & dtlck->lv[0]; - - /* update the self address in the dtpage header */ - pxd = &p->header.self; - PXDaddress(pxd, nxaddr); - - /* the dst page is the same as the src page, i.e., - * linelock for afterimage of the whole page; - */ - lv->offset = 0; - lv->length = p->header.maxslot; - dtlck->index++; - - /* update the buffer extent descriptor of the dtpage */ - xsize = xlen << JFS_SBI(ip->i_sb)->l2bsize; - - /* unpin the relocated page */ - DT_PUTPAGE(mp); - jfs_info("dtRelocate: target dtpage relocated."); - - /* the moved extent is dtpage, then a LOG_NOREDOPAGE log rec - * needs to be written (in logredo(), the LOG_NOREDOPAGE log rec - * will also force a bmap update ). - */ - - /* - * 3. acquire maplock for the source extent to be freed; - */ - /* for dtpage relocation, write a LOG_NOREDOPAGE record - * for the source dtpage (logredo() will init NoRedoPage - * filter and will also update bmap for free of the source - * dtpage), and upadte bmap for free of the source dtpage; - */ - tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE); - pxdlock = (struct pxd_lock *) & tlck->lock; - pxdlock->flag = mlckFREEPXD; - PXDaddress(&pxdlock->pxd, oxaddr); - PXDlength(&pxdlock->pxd, xlen); - pxdlock->index = 1; - - /* - * 4. update the parent router entry for relocation; - * - * acquire tlck for the parent entry covering the target dtpage; - * write LOG_REDOPAGE to apply after image only; - */ - jfs_info("dtRelocate: update parent router entry."); - tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY); - dtlck = (struct dt_lock *) & tlck->lock; - lv = & dtlck->lv[dtlck->index]; - - /* update the PXD with the new address */ - stbl = DT_GETSTBL(pp); - pxd = (pxd_t *) & pp->slot[stbl[index]]; - PXDaddress(pxd, nxaddr); - lv->offset = stbl[index]; - lv->length = 1; - dtlck->index++; - - /* unpin the parent dtpage */ - DT_PUTPAGE(pmp); - - return rc; -} - -/* - * NAME: dtSearchNode() - * - * FUNCTION: Search for an dtpage containing a specified address - * This function is mainly used by defragfs utility. - * - * NOTE: Search result on stack, the found page is pinned at exit. - * The result page must be an internal dtpage. - * lmxaddr give the address of the left most page of the - * dtree level, in which the required dtpage resides. - */ -static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd, - struct btstack * btstack) -{ - int rc = 0; - s64 bn; - struct metapage *mp; - dtpage_t *p; - int psize = 288; /* initial in-line directory */ - s8 *stbl; - int i; - pxd_t *pxd; - struct btframe *btsp; - - BT_CLR(btstack); /* reset stack */ - - /* - * descend tree to the level with specified leftmost page - * - * by convention, root bn = 0. - */ - for (bn = 0;;) { - /* get/pin the page to search */ - DT_GETPAGE(ip, bn, mp, psize, p, rc); - if (rc) - return rc; - - /* does the xaddr of leftmost page of the levevl - * matches levevl search key ? - */ - if (p->header.flag & BT_ROOT) { - if (lmxaddr == 0) - break; - } else if (addressPXD(&p->header.self) == lmxaddr) - break; - - /* - * descend down to leftmost child page - */ - if (p->header.flag & BT_LEAF) { - DT_PUTPAGE(mp); - return -ESTALE; - } - - /* get the leftmost entry */ - stbl = DT_GETSTBL(p); - pxd = (pxd_t *) & p->slot[stbl[0]]; - - /* get the child page block address */ - bn = addressPXD(pxd); - psize = lengthPXD(pxd) << JFS_SBI(ip->i_sb)->l2bsize; - /* unpin the parent page */ - DT_PUTPAGE(mp); - } - - /* - * search each page at the current levevl - */ - loop: - stbl = DT_GETSTBL(p); - for (i = 0; i < p->header.nextindex; i++) { - pxd = (pxd_t *) & p->slot[stbl[i]]; - - /* found the specified router entry */ - if (addressPXD(pxd) == addressPXD(kpxd) && - lengthPXD(pxd) == lengthPXD(kpxd)) { - btsp = btstack->top; - btsp->bn = bn; - btsp->index = i; - btsp->mp = mp; - - return 0; - } - } - - /* get the right sibling page if any */ - if (p->header.next) - bn = le64_to_cpu(p->header.next); - else { - DT_PUTPAGE(mp); - return -ESTALE; - } - - /* unpin current page */ - DT_PUTPAGE(mp); - - /* get the right sibling page */ - DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); - if (rc) - return rc; - - goto loop; -} -#endif /* _NOTYET */ - /* * dtRelink() * @@ -2916,7 +2613,7 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot) * fsck.jfs should really fix this, but it currently does not. * Called from jfs_readdir when bad index is detected. */ -static void add_missing_indices(struct inode *inode, s64 bn) +static int add_missing_indices(struct inode *inode, s64 bn) { struct ldtentry *d; struct dt_lock *dtlck; @@ -2925,7 +2622,7 @@ static void add_missing_indices(struct inode *inode, s64 bn) struct lv *lv; struct metapage *mp; dtpage_t *p; - int rc; + int rc = 0; s8 *stbl; tid_t tid; struct tlock *tlck; @@ -2950,6 +2647,16 @@ static void add_missing_indices(struct inode *inode, s64 bn) stbl = DT_GETSTBL(p); for (i = 0; i < p->header.nextindex; i++) { + if (stbl[i] < 0) { + jfs_err("jfs: add_missing_indices: Invalid stbl[%d] = %d for inode %ld, block = %lld", + i, stbl[i], (long)inode->i_ino, (long long)bn); + rc = -EIO; + + DT_PUTPAGE(mp); + txAbort(tid, 0); + goto end; + } + d = (struct ldtentry *) &p->slot[stbl[i]]; index = le32_to_cpu(d->index); if ((index < 2) || (index >= JFS_IP(inode)->next_index)) { @@ -2967,6 +2674,7 @@ static void add_missing_indices(struct inode *inode, s64 bn) (void) txCommit(tid, 1, &inode, 0); end: txEnd(tid); + return rc; } /* @@ -2977,7 +2685,7 @@ struct jfs_dirent { loff_t position; int ino; u16 name_len; - char name[0]; + char name[]; }; /* @@ -3195,6 +2903,14 @@ int jfs_readdir(struct file *file, struct dir_context *ctx) stbl = DT_GETSTBL(p); for (i = index; i < p->header.nextindex; i++) { + if (stbl[i] < 0 || stbl[i] >= DTPAGEMAXSLOT) { + jfs_err("JFS: Invalid stbl[%d] = %d for inode %ld, block = %lld", + i, stbl[i], (long)ip->i_ino, (long long)bn); + free_page(dirent_buf); + DT_PUTPAGE(mp); + return -EIO; + } + d = (struct ldtentry *) & p->slot[stbl[i]]; if (((long) jfs_dirent + d->namlen + 1) > @@ -3312,7 +3028,8 @@ skip_one: } if (fix_page) { - add_missing_indices(ip, bn); + if ((rc = add_missing_indices(ip, bn))) + goto out; page_fixed = 1; } @@ -3390,6 +3107,13 @@ static int dtReadFirst(struct inode *ip, struct btstack * btstack) /* get the leftmost entry */ stbl = DT_GETSTBL(p); + + if (stbl[0] < 0 || stbl[0] >= DTPAGEMAXSLOT) { + DT_PUTPAGE(mp); + jfs_error(ip->i_sb, "stbl[0] out of bound\n"); + return -EIO; + } + xd = (pxd_t *) & p->slot[stbl[0]]; /* get the child page block address */ |
