Pull jfs updates from Dave Kleikamp: "More robust data integrity checking and some fixes" * tag 'jfs-7.1' of github.com:kleikamp/linux-shaggy: jfs: avoid -Wtautological-constant-out-of-range-compare warning again JFS: always load filesystem UUID during mount jfs: hold LOG_LOCK on umount to avoid null-ptr-deref jfs: Set the lbmDone flag at the end of lbmIODone jfs: fix corrupted list in dbUpdatePMap jfs: add dmapctl integrity check to prevent invalid operations jfs: add dtpage integrity check to prevent index/pointer overflows jfs: add dtroot integrity check to prevent index out-of-bounds
Unified · Split
| @@ -133,6 +133,93 @@ static const s8 budtab[256] = { · 132 unmodified lines | |||
| 133 | 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 | 133 | 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 |
| 134 | }; | 134 | }; |
| 135 | 135 | ||
| 136 | /* | ||
| 137 | * check_dmapctl - Validate integrity of a dmapctl structure | ||
| 138 | * @dcp: Pointer to the dmapctl structure to check | ||
| 139 | * | ||
| 140 | * Return: true if valid, false if corrupted | ||
| 141 | */ | ||
| 142 | static bool check_dmapctl(struct dmapctl *dcp) | ||
| 143 | { | ||
| 144 | s8 budmin = dcp->budmin; | ||
| 145 | u32 nleafs, l2nleafs, leafidx, height; | ||
| 146 | int i; | ||
| 147 | |||
| 148 | nleafs = le32_to_cpu(dcp->nleafs); | ||
| 149 | /* Check basic field ranges */ | ||
| 150 | if (unlikely(nleafs > LPERCTL)) { | ||
| 151 | jfs_err("dmapctl: invalid nleafs %u (max %u)", | ||
| 152 | nleafs, LPERCTL); | ||
| 153 | return false; | ||
| 154 | } | ||
| 155 | |||
| 156 | l2nleafs = le32_to_cpu(dcp->l2nleafs); | ||
| 157 | if (unlikely(l2nleafs > L2LPERCTL)) { | ||
| 158 | jfs_err("dmapctl: invalid l2nleafs %u (max %u)", | ||
| 159 | l2nleafs, L2LPERCTL); | ||
| 160 | return false; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* Verify nleafs matches l2nleafs (must be power of two) */ | ||
| 164 | if (unlikely((1U << l2nleafs) != nleafs)) { | ||
| 165 | jfs_err("dmapctl: nleafs %u != 2^%u", | ||
| 166 | nleafs, l2nleafs); | ||
| 167 | return false; | ||
| 168 | } | ||
| 169 | |||
| 170 | leafidx = le32_to_cpu(dcp->leafidx); | ||
| 171 | /* Check leaf index matches expected position */ | ||
| 172 | if (unlikely(leafidx != CTLLEAFIND)) { | ||
| 173 | jfs_err("dmapctl: invalid leafidx %u (expected %u)", | ||
| 174 | leafidx, CTLLEAFIND); | ||
| 175 | return false; | ||
| 176 | } | ||
| 177 | |||
| 178 | height = le32_to_cpu(dcp->height); | ||
| 179 | /* Check tree height is within valid range */ | ||
| 180 | if (unlikely(height > (L2LPERCTL >> 1))) { | ||
| 181 | jfs_err("dmapctl: invalid height %u (max %u)", | ||
| 182 | height, L2LPERCTL >> 1); | ||
| 183 | return false; | ||
| 184 | } | ||
| 185 | |||
| 186 | /* Check budmin is valid (cannot be NOFREE for non-empty tree) */ | ||
| 187 | if (budmin == NOFREE) { | ||
| 188 | if (unlikely(nleafs > 0)) { | ||
| 189 | jfs_err("dmapctl: budmin is NOFREE but nleafs %u", | ||
| 190 | nleafs); | ||
| 191 | return false; | ||
| 192 | } | ||
| 193 | } else if (unlikely(budmin < BUDMIN)) { | ||
| 194 | jfs_err("dmapctl: invalid budmin %d (min %d)", | ||
| 195 | budmin, BUDMIN); | ||
| 196 | return false; | ||
| 197 | } | ||
| 198 | |||
| 199 | /* Check leaf nodes fit within stree array */ | ||
| 200 | if (unlikely(leafidx + nleafs > CTLTREESIZE)) { | ||
| 201 | jfs_err("dmapctl: leaf range exceeds stree size (end %u > %u)", | ||
| 202 | leafidx + nleafs, CTLTREESIZE); | ||
| 203 | return false; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* Check leaf nodes have valid values */ | ||
| 207 | for (i = leafidx; i < leafidx + nleafs; i++) { | ||
| 208 | s8 val = dcp->stree[i]; | ||
| 209 | |||
| 210 | if (unlikely(val < NOFREE)) { | ||
| 211 | jfs_err("dmapctl: invalid leaf value %d at index %d", | ||
| 212 | val, i); | ||
| 213 | return false; | ||
| 214 | } else if (unlikely(val > 31)) { | ||
| 215 | jfs_err("dmapctl: leaf value %d too large at index %d", val, i); | ||
| 216 | return false; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | return true; | ||
| 221 | } | ||
| 222 | |||
| 136 | /* | 223 | /* |
| 137 | * NAME: dbMount() | 224 | * NAME: dbMount() |
| 138 | * | 225 | * |
| @@ -1372,7 +1459,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) · 1233 unmodified lines | |||
| 1372 | dcp = (struct dmapctl *) mp->data; | 1459 | dcp = (struct dmapctl *) mp->data; |
| 1373 | budmin = dcp->budmin; | 1460 | budmin = dcp->budmin; |
| 1374 | 1461 | ||
| 1375 | if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { | 1462 | if (unlikely(!check_dmapctl(dcp))) { |
| 1376 | jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); | 1463 | jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); |
| 1377 | release_metapage(mp); | 1464 | release_metapage(mp); |
| 1378 | return -EIO; | 1465 | return -EIO; |
| @@ -1702,7 +1789,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) · 323 unmodified lines | |||
| 1702 | dcp = (struct dmapctl *) mp->data; | 1789 | dcp = (struct dmapctl *) mp->data; |
| 1703 | budmin = dcp->budmin; | 1790 | budmin = dcp->budmin; |
| 1704 | 1791 | ||
| 1705 | if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { | 1792 | if (unlikely(!check_dmapctl(dcp))) { |
| 1706 | jfs_error(bmp->db_ipbmap->i_sb, | 1793 | jfs_error(bmp->db_ipbmap->i_sb, |
| 1707 | "Corrupt dmapctl page\n"); | 1794 | "Corrupt dmapctl page\n"); |
| 1708 | release_metapage(mp); | 1795 | release_metapage(mp); |
| @@ -2485,7 +2572,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) · 776 unmodified lines | |||
| 2485 | return -EIO; | 2572 | return -EIO; |
| 2486 | dcp = (struct dmapctl *) mp->data; | 2573 | dcp = (struct dmapctl *) mp->data; |
| 2487 | 2574 | ||
| 2488 | if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { | 2575 | if (unlikely(!check_dmapctl(dcp))) { |
| 2489 | jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); | 2576 | jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); |
| 2490 | release_metapage(mp); | 2577 | release_metapage(mp); |
| 2491 | return -EIO; | 2578 | return -EIO; |
| @@ -3454,6 +3541,11 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) · 962 unmodified lines | |||
| 3454 | return -EIO; | 3541 | return -EIO; |
| 3455 | } | 3542 | } |
| 3456 | l2dcp = (struct dmapctl *) l2mp->data; | 3543 | l2dcp = (struct dmapctl *) l2mp->data; |
| 3544 | if (unlikely(!check_dmapctl(l2dcp))) { | ||
| 3545 | jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); | ||
| 3546 | release_metapage(l2mp); | ||
| 3547 | return -EIO; | ||
| 3548 | } | ||
| 3457 | 3549 | ||
| 3458 | /* compute start L1 */ | 3550 | /* compute start L1 */ |
| 3459 | k = blkno >> L2MAXL1SIZE; | 3551 | k = blkno >> L2MAXL1SIZE; |
| @@ -3471,6 +3563,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) · 11 unmodified lines | |||
| 3471 | if (l1mp == NULL) | 3563 | if (l1mp == NULL) |
| 3472 | goto errout; | 3564 | goto errout; |
| 3473 | l1dcp = (struct dmapctl *) l1mp->data; | 3565 | l1dcp = (struct dmapctl *) l1mp->data; |
| 3566 | if (unlikely(!check_dmapctl(l1dcp))) { | ||
| 3567 | jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); | ||
| 3568 | goto errout; | ||
| 3569 | } | ||
| 3474 | 3570 | ||
| 3475 | /* compute start L0 */ | 3571 | /* compute start L0 */ |
| 3476 | j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; | 3572 | j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; |
| @@ -3484,6 +3580,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) · 7 unmodified lines | |||
| 3484 | goto errout; | 3580 | goto errout; |
| 3485 | 3581 | ||
| 3486 | l1dcp = (struct dmapctl *) l1mp->data; | 3582 | l1dcp = (struct dmapctl *) l1mp->data; |
| 3583 | if (unlikely(!check_dmapctl(l1dcp))) { | ||
| 3584 | jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); | ||
| 3585 | goto errout; | ||
| 3586 | } | ||
| 3487 | 3587 | ||
| 3488 | /* compute start L0 */ | 3588 | /* compute start L0 */ |
| 3489 | j = 0; | 3589 | j = 0; |
| @@ -3503,6 +3603,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) · 13 unmodified lines | |||
| 3503 | if (l0mp == NULL) | 3603 | if (l0mp == NULL) |
| 3504 | goto errout; | 3604 | goto errout; |
| 3505 | l0dcp = (struct dmapctl *) l0mp->data; | 3605 | l0dcp = (struct dmapctl *) l0mp->data; |
| 3606 | if (unlikely(!check_dmapctl(l0dcp))) { | ||
| 3607 | jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); | ||
| 3608 | goto errout; | ||
| 3609 | } | ||
| 3506 | 3610 | ||
| 3507 | /* compute start dmap */ | 3611 | /* compute start dmap */ |
| 3508 | i = (blkno & (MAXL0SIZE - 1)) >> | 3612 | i = (blkno & (MAXL0SIZE - 1)) >> |
| @@ -3518,6 +3622,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) · 9 unmodified lines | |||
| 3518 | goto errout; | 3622 | goto errout; |
| 3519 | 3623 | ||
| 3520 | l0dcp = (struct dmapctl *) l0mp->data; | 3624 | l0dcp = (struct dmapctl *) l0mp->data; |
| 3625 | if (unlikely(!check_dmapctl(l0dcp))) { | ||
| 3626 | jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); | ||
| 3627 | goto errout; | ||
| 3628 | } | ||
| 3521 | 3629 | ||
| 3522 | /* compute start dmap */ | 3630 | /* compute start dmap */ |
| 3523 | i = 0; | 3631 | i = 0; |
| @@ -115,10 +115,7 @@ struct dtsplit { · 114 unmodified lines | |||
| 115 | do { \ | 115 | do { \ |
| 116 | BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot); \ | 116 | BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot); \ |
| 117 | if (!(RC)) { \ | 117 | if (!(RC)) { \ |
| 118 | if (((P)->header.nextindex > \ | 118 | if ((BN) && !check_dtpage(P)) { \ |
| 119 | (((BN) == 0) ? DTROOTMAXSLOT : (P)->header.maxslot)) || \ | ||
| 120 | ((BN) && (((P)->header.maxslot > DTPAGEMAXSLOT) || \ | ||
| 121 | ((P)->header.stblindex >= DTPAGEMAXSLOT)))) { \ | ||
| 122 | BT_PUTPAGE(MP); \ | 119 | BT_PUTPAGE(MP); \ |
| 123 | jfs_error((IP)->i_sb, \ | 120 | jfs_error((IP)->i_sb, \ |
| 124 | "DT_GETPAGE: dtree page corrupt\n"); \ | 121 | "DT_GETPAGE: dtree page corrupt\n"); \ |
| @@ -4297,3 +4294,190 @@ int dtModify(tid_t tid, struct inode *ip, · 4172 unmodified lines | |||
| 4297 | 4294 | ||
| 4298 | return 0; | 4295 | return 0; |
| 4299 | } | 4296 | } |
| 4297 | |||
| 4298 | bool check_dtroot(dtroot_t *p) | ||
| 4299 | { | ||
| 4300 | DECLARE_BITMAP(bitmap, DTROOTMAXSLOT) = {0}; | ||
| 4301 | int i; | ||
| 4302 | |||
| 4303 | /* freecnt cannot be negative or exceed DTROOTMAXSLOT-1 | ||
| 4304 | * (since slot[0] is occupied by the header). | ||
| 4305 | */ | ||
| 4306 | if (unlikely(p->header.freecnt < 0 || | ||
| 4307 | p->header.freecnt > DTROOTMAXSLOT - 1)) { | ||
| 4308 | jfs_err("Bad freecnt:%d in dtroot\n", p->header.freecnt); | ||
| 4309 | return false; | ||
| 4310 | } else if (p->header.freecnt == 0) { | ||
| 4311 | /* No free slots: freelist must be -1 */ | ||
| 4312 | if (unlikely(p->header.freelist != -1)) { | ||
| 4313 | jfs_err("freecnt=0, but freelist=%d in dtroot\n", | ||
| 4314 | p->header.freelist); | ||
| 4315 | return false; | ||
| 4316 | } | ||
| 4317 | } else { | ||
| 4318 | int fsi, i; | ||
| 4319 | /* When there are free slots, freelist must be a valid slot index in | ||
| 4320 | * 1~DTROOTMAXSLOT-1(since slot[0] is occupied by the header). | ||
| 4321 | */ | ||
| 4322 | if (unlikely(p->header.freelist < 1 || | ||
| 4323 | p->header.freelist >= DTROOTMAXSLOT)) { | ||
| 4324 | jfs_err("Bad freelist:%d in dtroot\n", p->header.freelist); | ||
| 4325 | return false; | ||
| 4326 | } | ||
| 4327 | |||
| 4328 | /* Traverse the free list to check validity of all node indices */ | ||
| 4329 | fsi = p->header.freelist; | ||
| 4330 | for (i = 0; i < p->header.freecnt - 1; i++) { | ||
| 4331 | /* Check for duplicate indices in the free list */ | ||
| 4332 | if (unlikely(__test_and_set_bit(fsi, bitmap))) { | ||
| 4333 | jfs_err("duplicate index%d in slot in dtroot\n", fsi); | ||
| 4334 | return false; | ||
| 4335 | } | ||
| 4336 | fsi = p->slot[fsi].next; | ||
| 4337 | |||
| 4338 | /* Ensure the next slot index in the free list is valid */ | ||
| 4339 | if (unlikely(fsi < 1 || fsi >= DTROOTMAXSLOT)) { | ||
| 4340 | jfs_err("Bad index:%d in slot in dtroot\n", fsi); | ||
| 4341 | return false; | ||
| 4342 | } | ||
| 4343 | } | ||
| 4344 | |||
| 4345 | /* The last node in the free list must terminate with next = -1 */ | ||
| 4346 | if (unlikely(p->slot[fsi].next != -1)) { | ||
| 4347 | jfs_err("Bad next:%d of the last slot in dtroot\n", | ||
| 4348 | p->slot[fsi].next); | ||
| 4349 | return false; | ||
| 4350 | } | ||
| 4351 | } | ||
| 4352 | |||
| 4353 | /* Validate nextindex (next free entry index in stbl) | ||
| 4354 | * stbl array has size 8 (indices 0~7). | ||
| 4355 | * It may get set to 8 when the last free slot has been filled. | ||
| 4356 | */ | ||
| 4357 | if (unlikely(p->header.nextindex > ARRAY_SIZE(p->header.stbl))) { | ||
| 4358 | jfs_err("Bad nextindex:%d in dtroot\n", p->header.nextindex); | ||
| 4359 | return false; | ||
| 4360 | } | ||
| 4361 | |||
| 4362 | /* Validate index validity of stbl array (8 elements) | ||
| 4363 | * Each entry in stbl is a slot index, with valid range: -1 (invalid) | ||
| 4364 | * or 0~8 (slot[0]~slot[8]) | ||
| 4365 | */ | ||
| 4366 | for (i = 0; i < p->header.nextindex; i++) { | ||
| 4367 | int idx = p->header.stbl[i]; | ||
| 4368 | |||
| 4369 | if (unlikely(idx < 0 || idx >= 9)) { | ||
| 4370 | jfs_err("Bad index:%d of stbl[%d] in dtroot\n", idx, i); | ||
| 4371 | return false; /* stbl entry points out of slot array range */ | ||
| 4372 | } | ||
| 4373 | |||
| 4374 | /* Check for duplicate valid indices (skip check for idx=0) */ | ||
| 4375 | if (unlikely(idx && __test_and_set_bit(idx, bitmap))) { | ||
| 4376 | jfs_err("Duplicate index:%d in stbl in dtroot\n", idx); | ||
| 4377 | return false; | ||
| 4378 | } | ||
| 4379 | } | ||
| 4380 | |||
| 4381 | return true; | ||
| 4382 | } | ||
| 4383 | |||
| 4384 | bool check_dtpage(dtpage_t *p) | ||
| 4385 | { | ||
| 4386 | DECLARE_BITMAP(bitmap, DTPAGEMAXSLOT) = {0}; | ||
| 4387 | const int stblsize = ((PSIZE >> L2DTSLOTSIZE) + 31) >> L2DTSLOTSIZE; | ||
| 4388 | int i; | ||
| 4389 | |||
| 4390 | /* Validate maxslot (maximum number of slots in the page) | ||
| 4391 | * dtpage_t slot array is defined to hold up to DTPAGEMAXSLOT (128) slots | ||
| 4392 | */ | ||
| 4393 | if (unlikely(p->header.maxslot != DTPAGEMAXSLOT)) { | ||
| 4394 | jfs_err("Bad maxslot:%d in dtpage (expected %d)\n", | ||
| 4395 | p->header.maxslot, DTPAGEMAXSLOT); | ||
| 4396 | return false; | ||
| 4397 | } | ||
| 4398 | |||
| 4399 | /* freecnt cannot be negative or exceed DTPAGEMAXSLOT-1 | ||
| 4400 | * (since slot[0] is occupied by the header). | ||
| 4401 | */ | ||
| 4402 | if (unlikely(p->header.freecnt < 0 || | ||
| 4403 | p->header.freecnt > DTPAGEMAXSLOT - 1)) { | ||
| 4404 | jfs_err("Bad freecnt:%d in dtpage\n", p->header.freecnt); | ||
| 4405 | return false; | ||
| 4406 | } else if (p->header.freecnt == 0) { | ||
| 4407 | /* No free slots: freelist must be -1 */ | ||
| 4408 | if (unlikely(p->header.freelist != -1)) { | ||
| 4409 | jfs_err("freecnt=0 but freelist=%d in dtpage\n", | ||
| 4410 | p->header.freelist); | ||
| 4411 | return false; | ||
| 4412 | } | ||
| 4413 | } else { | ||
| 4414 | int fsi; | ||
| 4415 | |||
| 4416 | if (unlikely(p->header.freelist < 1)) { | ||
| 4417 | jfs_err("Bad freelist:%d in dtpage\n", p->header.freelist); | ||
| 4418 | return false; | ||
| 4419 | } | ||
| 4420 | |||
| 4421 | /* Traverse the free list to check validity of all node indices */ | ||
| 4422 | fsi = p->header.freelist; | ||
| 4423 | for (i = 0; i < p->header.freecnt - 1; i++) { | ||
| 4424 | /* Check for duplicate indices in the free list */ | ||
| 4425 | if (unlikely(__test_and_set_bit(fsi, bitmap))) { | ||
| 4426 | jfs_err("duplicate index%d in slot in dtpage\n", fsi); | ||
| 4427 | return false; | ||
| 4428 | } | ||
| 4429 | fsi = p->slot[fsi].next; | ||
| 4430 | |||
| 4431 | /* Ensure the next slot index in the free list is valid */ | ||
| 4432 | if (unlikely(fsi < 1 || fsi >= DTPAGEMAXSLOT)) { | ||
| 4433 | jfs_err("Bad index:%d in slot in dtpage\n", fsi); | ||
| 4434 | return false; | ||
| 4435 | } | ||
| 4436 | } | ||
| 4437 | |||
| 4438 | /* The last node in the free list must terminate with next = -1 */ | ||
| 4439 | if (unlikely(p->slot[fsi].next != -1)) { | ||
| 4440 | jfs_err("Bad next:%d of the last slot in dtpage\n", | ||
| 4441 | p->slot[fsi].next); | ||
| 4442 | return false; | ||
| 4443 | } | ||
| 4444 | } | ||
| 4445 | |||
| 4446 | /* stbl must be little then DTPAGEMAXSLOT */ | ||
| 4447 | if (unlikely(p->header.stblindex >= DTPAGEMAXSLOT - stblsize)) { | ||
| 4448 | jfs_err("Bad stblindex:%d in dtpage (stbl size %d)\n", | ||
| 4449 | p->header.stblindex, stblsize); | ||
| 4450 | return false; | ||
| 4451 | } | ||
| 4452 | |||
| 4453 | /* nextindex must be little then stblsize*32 */ | ||
| 4454 | if (unlikely(p->header.nextindex > (stblsize << L2DTSLOTSIZE))) { | ||
| 4455 | jfs_err("Bad nextindex:%d in dtpage (stbl size %d)\n", | ||
| 4456 | p->header.nextindex, stblsize); | ||
| 4457 | return false; | ||
| 4458 | } | ||
| 4459 | |||
| 4460 | /* Validate stbl entries | ||
| 4461 | * Each entry is a slot index, valid range: -1 (invalid) or | ||
| 4462 | * [0, nextindex-1] (valid data slots) | ||
| 4463 | * (stblindex and higher slots are reserved for stbl itself) | ||
| 4464 | */ | ||
| 4465 | for (i = 0; i < p->header.nextindex; i++) { | ||
| 4466 | int idx = DT_GETSTBL(p)[i]; | ||
| 4467 | |||
| 4468 | /* Check if index is out of valid data slot range */ | ||
| 4469 | if (unlikely(idx < 1 || idx >= DTPAGEMAXSLOT)) { | ||
| 4470 | jfs_err("Bad stbl[%d] index:%d (stblindex %d) in dtpage\n", | ||
| 4471 | i, idx, p->header.stblindex); | ||
| 4472 | return false; | ||
| 4473 | } | ||
| 4474 | |||
| 4475 | /* Check for duplicate valid indices (skip -1) */ | ||
| 4476 | if (unlikely(__test_and_set_bit(idx, bitmap))) { | ||
| 4477 | jfs_err("Duplicate index:%d in stbl of dtpage\n", idx); | ||
| 4478 | return false; | ||
| 4479 | } | ||
| 4480 | } | ||
| 4481 | |||
| 4482 | return true; | ||
| 4483 | } | ||
| @@ -253,4 +253,8 @@ extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key, · 252 unmodified lines | |||
| 253 | ino_t * orig_ino, ino_t new_ino, int flag); | 253 | ino_t * orig_ino, ino_t new_ino, int flag); |
| 254 | 254 | ||
| 255 | extern int jfs_readdir(struct file *file, struct dir_context *ctx); | 255 | extern int jfs_readdir(struct file *file, struct dir_context *ctx); |
| 256 | |||
| 257 | extern bool check_dtroot(dtroot_t *p); | ||
| 258 | |||
| 259 | extern bool check_dtpage(dtpage_t *p); | ||
| 256 | #endif /* !_H_JFS_DTREE */ | 260 | #endif /* !_H_JFS_DTREE */ |
| @@ -3102,6 +3102,10 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) · 3101 unmodified lines | |||
| 3102 | 3102 | ||
| 3103 | if (S_ISDIR(ip->i_mode)) { | 3103 | if (S_ISDIR(ip->i_mode)) { |
| 3104 | memcpy(&jfs_ip->u.dir, &dip->u._dir, 384); | 3104 | memcpy(&jfs_ip->u.dir, &dip->u._dir, 384); |
| 3105 | if (!check_dtroot(&jfs_ip->i_dtroot)) { | ||
| 3106 | jfs_error(ip->i_sb, "Corrupt dtroot\n"); | ||
| 3107 | return -EIO; | ||
| 3108 | } | ||
| 3105 | } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { | 3109 | } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { |
| 3106 | memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); | 3110 | memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); |
| 3107 | } else | 3111 | } else |
| @@ -74,12 +74,6 @@ static struct lbuf *log_redrive_list; · 73 unmodified lines | |||
| 74 | static DEFINE_SPINLOCK(log_redrive_lock); | 74 | static DEFINE_SPINLOCK(log_redrive_lock); |
| 75 | 75 | ||
| 76 | 76 | ||
| 77 | /* | ||
| 78 | * log read/write serialization (per log) | ||
| 79 | */ | ||
| 80 | #define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) | ||
| 81 | #define LOG_LOCK(log) mutex_lock(&((log)->loglock)) | ||
| 82 | #define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) | ||
| 83 | 77 | ||
| 84 | 78 | ||
| 85 | /* | 79 | /* |
| @@ -204,9 +198,13 @@ static void write_special_inodes(struct jfs_log *log, · 118 unmodified lines | |||
| 204 | struct jfs_sb_info *sbi; | 198 | struct jfs_sb_info *sbi; |
| 205 | 199 | ||
| 206 | list_for_each_entry(sbi, &log->sb_list, log_list) { | 200 | list_for_each_entry(sbi, &log->sb_list, log_list) { |
| 207 | writer(sbi->ipbmap->i_mapping); | 201 | /* These pointers can be NULL before list_del during umount */ |
| 208 | writer(sbi->ipimap->i_mapping); | 202 | if (sbi->ipbmap) |
| 209 | writer(sbi->direct_inode->i_mapping); | 203 | writer(sbi->ipbmap->i_mapping); |
| 204 | if (sbi->ipimap) | ||
| 205 | writer(sbi->ipimap->i_mapping); | ||
| 206 | if (sbi->direct_inode) | ||
| 207 | writer(sbi->direct_inode->i_mapping); | ||
| 210 | } | 208 | } |
| 211 | } | 209 | } |
| 212 | 210 | ||
| @@ -2180,8 +2178,6 @@ static void lbmIODone(struct bio *bio) · 1967 unmodified lines | |||
| 2180 | 2178 | ||
| 2181 | LCACHE_LOCK(flags); /* disable+lock */ | 2179 | LCACHE_LOCK(flags); /* disable+lock */ |
| 2182 | 2180 | ||
| 2183 | bp->l_flag |= lbmDONE; | ||
| 2184 | |||
| 2185 | if (bio->bi_status) { | 2181 | if (bio->bi_status) { |
| 2186 | bp->l_flag |= lbmERROR; | 2182 | bp->l_flag |= lbmERROR; |
| 2187 | 2183 | ||
| @@ -2196,12 +2192,10 @@ static void lbmIODone(struct bio *bio) · 8 unmodified lines | |||
| 2196 | if (bp->l_flag & lbmREAD) { | 2192 | if (bp->l_flag & lbmREAD) { |
| 2197 | bp->l_flag &= ~lbmREAD; | 2193 | bp->l_flag &= ~lbmREAD; |
| 2198 | 2194 | ||
| 2199 | LCACHE_UNLOCK(flags); /* unlock+enable */ | ||
| 2200 | |||
| 2201 | /* wakeup I/O initiator */ | 2195 | /* wakeup I/O initiator */ |
| 2202 | LCACHE_WAKEUP(&bp->l_ioevent); | 2196 | LCACHE_WAKEUP(&bp->l_ioevent); |
| 2203 | 2197 | ||
| 2204 | return; | 2198 | goto out; |
| 2205 | } | 2199 | } |
| 2206 | 2200 | ||
| 2207 | /* | 2201 | /* |
| @@ -2225,8 +2219,7 @@ static void lbmIODone(struct bio *bio) · 17 unmodified lines | |||
| 2225 | 2219 | ||
| 2226 | if (bp->l_flag & lbmDIRECT) { | 2220 | if (bp->l_flag & lbmDIRECT) { |
| 2227 | LCACHE_WAKEUP(&bp->l_ioevent); | 2221 | LCACHE_WAKEUP(&bp->l_ioevent); |
| 2228 | LCACHE_UNLOCK(flags); | 2222 | goto out; |
| 2229 | return; | ||
| 2230 | } | 2223 | } |
| 2231 | 2224 | ||
| 2232 | tail = log->wqueue; | 2225 | tail = log->wqueue; |
| @@ -2278,8 +2271,6 @@ static void lbmIODone(struct bio *bio) · 45 unmodified lines | |||
| 2278 | * leave buffer for i/o initiator to dispose | 2271 | * leave buffer for i/o initiator to dispose |
| 2279 | */ | 2272 | */ |
| 2280 | if (bp->l_flag & lbmSYNC) { | 2273 | if (bp->l_flag & lbmSYNC) { |
| 2281 | LCACHE_UNLOCK(flags); /* unlock+enable */ | ||
| 2282 | |||
| 2283 | /* wakeup I/O initiator */ | 2274 | /* wakeup I/O initiator */ |
| 2284 | LCACHE_WAKEUP(&bp->l_ioevent); | 2275 | LCACHE_WAKEUP(&bp->l_ioevent); |
| 2285 | } | 2276 | } |
| @@ -2290,6 +2281,7 @@ static void lbmIODone(struct bio *bio) · 4 unmodified lines | |||
| 2290 | else if (bp->l_flag & lbmGC) { | 2281 | else if (bp->l_flag & lbmGC) { |
| 2291 | LCACHE_UNLOCK(flags); | 2282 | LCACHE_UNLOCK(flags); |
| 2292 | lmPostGC(bp); | 2283 | lmPostGC(bp); |
| 2284 | LCACHE_LOCK(flags); /* disable+lock */ | ||
| 2293 | } | 2285 | } |
| 2294 | 2286 | ||
| 2295 | /* | 2287 | /* |
| @@ -2302,9 +2294,11 @@ static void lbmIODone(struct bio *bio) · 6 unmodified lines | |||
| 2302 | assert(bp->l_flag & lbmRELEASE); | 2294 | assert(bp->l_flag & lbmRELEASE); |
| 2303 | assert(bp->l_flag & lbmFREE); | 2295 | assert(bp->l_flag & lbmFREE); |
| 2304 | lbmfree(bp); | 2296 | lbmfree(bp); |
| 2305 | |||
| 2306 | LCACHE_UNLOCK(flags); /* unlock+enable */ | ||
| 2307 | } | 2297 | } |
| 2298 | |||
| 2299 | out: | ||
| 2300 | bp->l_flag |= lbmDONE; | ||
| 2301 | LCACHE_UNLOCK(flags); | ||
| 2308 | } | 2302 | } |
| 2309 | 2303 | ||
| 2310 | int jfsIOWait(void *arg) | 2304 | int jfsIOWait(void *arg) |
| @@ -402,6 +402,13 @@ struct jfs_log { · 401 unmodified lines | |||
| 402 | int no_integrity; /* 3: flag to disable journaling to disk */ | 402 | int no_integrity; /* 3: flag to disable journaling to disk */ |
| 403 | }; | 403 | }; |
| 404 | 404 | ||
| 405 | /* | ||
| 406 | * log read/write serialization (per log) | ||
| 407 | */ | ||
| 408 | #define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) | ||
| 409 | #define LOG_LOCK(log) mutex_lock(&((log)->loglock)) | ||
| 410 | #define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) | ||
| 411 | |||
| 405 | /* | 412 | /* |
| 406 | * Log flag | 413 | * Log flag |
| 407 | */ | 414 | */ |
| @@ -270,6 +270,7 @@ static inline struct metapage *alloc_metapage(gfp_t gfp_mask) · 269 unmodified lines | |||
| 270 | mp->clsn = 0; | 270 | mp->clsn = 0; |
| 271 | mp->log = NULL; | 271 | mp->log = NULL; |
| 272 | init_waitqueue_head(&mp->wait); | 272 | init_waitqueue_head(&mp->wait); |
| 273 | INIT_LIST_HEAD(&mp->synclist); | ||
| 273 | } | 274 | } |
| 274 | return mp; | 275 | return mp; |
| 275 | } | 276 | } |
| @@ -379,7 +380,7 @@ static void remove_from_logsync(struct metapage *mp) · 103 unmodified lines | |||
| 379 | mp->lsn = 0; | 380 | mp->lsn = 0; |
| 380 | mp->clsn = 0; | 381 | mp->clsn = 0; |
| 381 | log->count--; | 382 | log->count--; |
| 382 | list_del(&mp->synclist); | 383 | list_del_init(&mp->synclist); |
| 383 | } | 384 | } |
| 384 | LOGSYNC_UNLOCK(log, flags); | 385 | LOGSYNC_UNLOCK(log, flags); |
| 385 | } | 386 | } |
| @@ -378,11 +378,12 @@ static int chkSuper(struct super_block *sb) · 377 unmodified lines | |||
| 378 | sbi->nbperpage = PSIZE >> sbi->l2bsize; | 378 | sbi->nbperpage = PSIZE >> sbi->l2bsize; |
| 379 | sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; | 379 | sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; |
| 380 | sbi->l2niperblk = sbi->l2bsize - L2DISIZE; | 380 | sbi->l2niperblk = sbi->l2bsize - L2DISIZE; |
| 381 | uuid_copy(&sbi->uuid, &j_sb->s_uuid); | ||
| 382 | |||
| 381 | if (sbi->mntflag & JFS_INLINELOG) | 383 | if (sbi->mntflag & JFS_INLINELOG) |
| 382 | sbi->logpxd = j_sb->s_logpxd; | 384 | sbi->logpxd = j_sb->s_logpxd; |
| 383 | else { | 385 | else { |
| 384 | sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); | 386 | sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); |
| 385 | uuid_copy(&sbi->uuid, &j_sb->s_uuid); | ||
| 386 | uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); | 387 | uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); |
| 387 | } | 388 | } |
| 388 | sbi->fsckpxd = j_sb->s_fsckpxd; | 389 | sbi->fsckpxd = j_sb->s_fsckpxd; |
| @@ -275,6 +275,7 @@ int txInit(void) · 274 unmodified lines | |||
| 275 | for (k = 0; k < nTxBlock; k++) { | 275 | for (k = 0; k < nTxBlock; k++) { |
| 276 | init_waitqueue_head(&TxBlock[k].gcwait); | 276 | init_waitqueue_head(&TxBlock[k].gcwait); |
| 277 | init_waitqueue_head(&TxBlock[k].waitor); | 277 | init_waitqueue_head(&TxBlock[k].waitor); |
| 278 | INIT_LIST_HEAD(&TxBlock[k].synclist); | ||
| 278 | } | 279 | } |
| 279 | 280 | ||
| 280 | for (k = 1; k < nTxBlock - 1; k++) { | 281 | for (k = 1; k < nTxBlock - 1; k++) { |
| @@ -974,7 +975,7 @@ static void txUnlock(struct tblock * tblk) · 693 unmodified lines | |||
| 974 | if (tblk->lsn) { | 975 | if (tblk->lsn) { |
| 975 | LOGSYNC_LOCK(log, flags); | 976 | LOGSYNC_LOCK(log, flags); |
| 976 | log->count--; | 977 | log->count--; |
| 977 | list_del(&tblk->synclist); | 978 | list_del_init(&tblk->synclist); |
| 978 | LOGSYNC_UNLOCK(log, flags); | 979 | LOGSYNC_UNLOCK(log, flags); |
| 979 | } | 980 | } |
| 980 | } | 981 | } |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include "jfs_superblock.h" | 20 | #include "jfs_superblock.h" |
| 21 | #include "jfs_dmap.h" | 21 | #include "jfs_dmap.h" |
| 22 | #include "jfs_imap.h" | 22 | #include "jfs_imap.h" |
| 23 | #include "jfs_logmgr.h" | ||
| 23 | #include "jfs_metapage.h" | 24 | #include "jfs_metapage.h" |
| 24 | #include "jfs_debug.h" | 25 | #include "jfs_debug.h" |
| 25 | 26 | ||
| @@ -57,6 +58,12 @@ int jfs_umount(struct super_block *sb) · 31 unmodified lines | |||
| 57 | */ | 58 | */ |
| 58 | jfs_flush_journal(log, 2); | 59 | jfs_flush_journal(log, 2); |
| 59 | 60 | ||
| 61 | /* | ||
| 62 | * Hold log lock so write_special_inodes (lmLogSync) cannot see | ||
| 63 | * this sbi with a NULL inode pointer while iterating log->sb_list. | ||
| 64 | */ | ||
| 65 | if (log) | ||
| 66 | LOG_LOCK(log); | ||
| 60 | /* | 67 | /* |
| 61 | * close fileset inode allocation map (aka fileset inode) | 68 | * close fileset inode allocation map (aka fileset inode) |
| 62 | */ | 69 | */ |
| @@ -95,6 +102,9 @@ int jfs_umount(struct super_block *sb) · 32 unmodified lines | |||
| 95 | */ | 102 | */ |
| 96 | filemap_write_and_wait(sbi->direct_inode->i_mapping); | 103 | filemap_write_and_wait(sbi->direct_inode->i_mapping); |
| 97 | 104 | ||
| 105 | if (log) | ||
| 106 | LOG_UNLOCK(log); | ||
| 107 | |||
| 98 | /* | 108 | /* |
| 99 | * ensure all file system file pages are propagated to their | 109 | * ensure all file system file pages are propagated to their |
| 100 | * home blocks on disk (and their in-memory buffer pages are | 110 | * home blocks on disk (and their in-memory buffer pages are |