Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'jfs-7.1' of github.com:kleikamp/linux-shaggy

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

+344 -30
+111 -3
fs/jfs/jfs_dmap.c
··· 134 134 }; 135 135 136 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 + 223 + /* 137 224 * NAME: dbMount() 138 225 * 139 226 * FUNCTION: initializate the block allocation map. ··· 1459 1372 dcp = (struct dmapctl *) mp->data; 1460 1373 budmin = dcp->budmin; 1461 1374 1462 - if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { 1375 + if (unlikely(!check_dmapctl(dcp))) { 1463 1376 jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); 1464 1377 release_metapage(mp); 1465 1378 return -EIO; ··· 1789 1702 dcp = (struct dmapctl *) mp->data; 1790 1703 budmin = dcp->budmin; 1791 1704 1792 - if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { 1705 + if (unlikely(!check_dmapctl(dcp))) { 1793 1706 jfs_error(bmp->db_ipbmap->i_sb, 1794 1707 "Corrupt dmapctl page\n"); 1795 1708 release_metapage(mp); ··· 2572 2485 return -EIO; 2573 2486 dcp = (struct dmapctl *) mp->data; 2574 2487 2575 - if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { 2488 + if (unlikely(!check_dmapctl(dcp))) { 2576 2489 jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n"); 2577 2490 release_metapage(mp); 2578 2491 return -EIO; ··· 3541 3454 return -EIO; 3542 3455 } 3543 3456 l2dcp = (struct dmapctl *) l2mp->data; 3457 + if (unlikely(!check_dmapctl(l2dcp))) { 3458 + jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); 3459 + release_metapage(l2mp); 3460 + return -EIO; 3461 + } 3544 3462 3545 3463 /* compute start L1 */ 3546 3464 k = blkno >> L2MAXL1SIZE; ··· 3563 3471 if (l1mp == NULL) 3564 3472 goto errout; 3565 3473 l1dcp = (struct dmapctl *) l1mp->data; 3474 + if (unlikely(!check_dmapctl(l1dcp))) { 3475 + jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); 3476 + goto errout; 3477 + } 3566 3478 3567 3479 /* compute start L0 */ 3568 3480 j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; ··· 3580 3484 goto errout; 3581 3485 3582 3486 l1dcp = (struct dmapctl *) l1mp->data; 3487 + if (unlikely(!check_dmapctl(l1dcp))) { 3488 + jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); 3489 + goto errout; 3490 + } 3583 3491 3584 3492 /* compute start L0 */ 3585 3493 j = 0; ··· 3603 3503 if (l0mp == NULL) 3604 3504 goto errout; 3605 3505 l0dcp = (struct dmapctl *) l0mp->data; 3506 + if (unlikely(!check_dmapctl(l0dcp))) { 3507 + jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); 3508 + goto errout; 3509 + } 3606 3510 3607 3511 /* compute start dmap */ 3608 3512 i = (blkno & (MAXL0SIZE - 1)) >> ··· 3622 3518 goto errout; 3623 3519 3624 3520 l0dcp = (struct dmapctl *) l0mp->data; 3521 + if (unlikely(!check_dmapctl(l0dcp))) { 3522 + jfs_error(ipbmap->i_sb, "Corrupt dmapctl page\n"); 3523 + goto errout; 3524 + } 3625 3525 3626 3526 /* compute start dmap */ 3627 3527 i = 0;
+188 -4
fs/jfs/jfs_dtree.c
··· 115 115 do { \ 116 116 BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot); \ 117 117 if (!(RC)) { \ 118 - if (((P)->header.nextindex > \ 119 - (((BN) == 0) ? DTROOTMAXSLOT : (P)->header.maxslot)) || \ 120 - ((BN) && (((P)->header.maxslot > DTPAGEMAXSLOT) || \ 121 - ((P)->header.stblindex >= DTPAGEMAXSLOT)))) { \ 118 + if ((BN) && !check_dtpage(P)) { \ 122 119 BT_PUTPAGE(MP); \ 123 120 jfs_error((IP)->i_sb, \ 124 121 "DT_GETPAGE: dtree page corrupt\n"); \ ··· 4293 4296 DT_PUTPAGE(mp); 4294 4297 4295 4298 return 0; 4299 + } 4300 + 4301 + bool check_dtroot(dtroot_t *p) 4302 + { 4303 + DECLARE_BITMAP(bitmap, DTROOTMAXSLOT) = {0}; 4304 + int i; 4305 + 4306 + /* freecnt cannot be negative or exceed DTROOTMAXSLOT-1 4307 + * (since slot[0] is occupied by the header). 4308 + */ 4309 + if (unlikely(p->header.freecnt < 0 || 4310 + p->header.freecnt > DTROOTMAXSLOT - 1)) { 4311 + jfs_err("Bad freecnt:%d in dtroot\n", p->header.freecnt); 4312 + return false; 4313 + } else if (p->header.freecnt == 0) { 4314 + /* No free slots: freelist must be -1 */ 4315 + if (unlikely(p->header.freelist != -1)) { 4316 + jfs_err("freecnt=0, but freelist=%d in dtroot\n", 4317 + p->header.freelist); 4318 + return false; 4319 + } 4320 + } else { 4321 + int fsi, i; 4322 + /* When there are free slots, freelist must be a valid slot index in 4323 + * 1~DTROOTMAXSLOT-1(since slot[0] is occupied by the header). 4324 + */ 4325 + if (unlikely(p->header.freelist < 1 || 4326 + p->header.freelist >= DTROOTMAXSLOT)) { 4327 + jfs_err("Bad freelist:%d in dtroot\n", p->header.freelist); 4328 + return false; 4329 + } 4330 + 4331 + /* Traverse the free list to check validity of all node indices */ 4332 + fsi = p->header.freelist; 4333 + for (i = 0; i < p->header.freecnt - 1; i++) { 4334 + /* Check for duplicate indices in the free list */ 4335 + if (unlikely(__test_and_set_bit(fsi, bitmap))) { 4336 + jfs_err("duplicate index%d in slot in dtroot\n", fsi); 4337 + return false; 4338 + } 4339 + fsi = p->slot[fsi].next; 4340 + 4341 + /* Ensure the next slot index in the free list is valid */ 4342 + if (unlikely(fsi < 1 || fsi >= DTROOTMAXSLOT)) { 4343 + jfs_err("Bad index:%d in slot in dtroot\n", fsi); 4344 + return false; 4345 + } 4346 + } 4347 + 4348 + /* The last node in the free list must terminate with next = -1 */ 4349 + if (unlikely(p->slot[fsi].next != -1)) { 4350 + jfs_err("Bad next:%d of the last slot in dtroot\n", 4351 + p->slot[fsi].next); 4352 + return false; 4353 + } 4354 + } 4355 + 4356 + /* Validate nextindex (next free entry index in stbl) 4357 + * stbl array has size 8 (indices 0~7). 4358 + * It may get set to 8 when the last free slot has been filled. 4359 + */ 4360 + if (unlikely(p->header.nextindex > ARRAY_SIZE(p->header.stbl))) { 4361 + jfs_err("Bad nextindex:%d in dtroot\n", p->header.nextindex); 4362 + return false; 4363 + } 4364 + 4365 + /* Validate index validity of stbl array (8 elements) 4366 + * Each entry in stbl is a slot index, with valid range: -1 (invalid) 4367 + * or 0~8 (slot[0]~slot[8]) 4368 + */ 4369 + for (i = 0; i < p->header.nextindex; i++) { 4370 + int idx = p->header.stbl[i]; 4371 + 4372 + if (unlikely(idx < 0 || idx >= 9)) { 4373 + jfs_err("Bad index:%d of stbl[%d] in dtroot\n", idx, i); 4374 + return false; /* stbl entry points out of slot array range */ 4375 + } 4376 + 4377 + /* Check for duplicate valid indices (skip check for idx=0) */ 4378 + if (unlikely(idx && __test_and_set_bit(idx, bitmap))) { 4379 + jfs_err("Duplicate index:%d in stbl in dtroot\n", idx); 4380 + return false; 4381 + } 4382 + } 4383 + 4384 + return true; 4385 + } 4386 + 4387 + bool check_dtpage(dtpage_t *p) 4388 + { 4389 + DECLARE_BITMAP(bitmap, DTPAGEMAXSLOT) = {0}; 4390 + const int stblsize = ((PSIZE >> L2DTSLOTSIZE) + 31) >> L2DTSLOTSIZE; 4391 + int i; 4392 + 4393 + /* Validate maxslot (maximum number of slots in the page) 4394 + * dtpage_t slot array is defined to hold up to DTPAGEMAXSLOT (128) slots 4395 + */ 4396 + if (unlikely(p->header.maxslot != DTPAGEMAXSLOT)) { 4397 + jfs_err("Bad maxslot:%d in dtpage (expected %d)\n", 4398 + p->header.maxslot, DTPAGEMAXSLOT); 4399 + return false; 4400 + } 4401 + 4402 + /* freecnt cannot be negative or exceed DTPAGEMAXSLOT-1 4403 + * (since slot[0] is occupied by the header). 4404 + */ 4405 + if (unlikely(p->header.freecnt < 0 || 4406 + p->header.freecnt > DTPAGEMAXSLOT - 1)) { 4407 + jfs_err("Bad freecnt:%d in dtpage\n", p->header.freecnt); 4408 + return false; 4409 + } else if (p->header.freecnt == 0) { 4410 + /* No free slots: freelist must be -1 */ 4411 + if (unlikely(p->header.freelist != -1)) { 4412 + jfs_err("freecnt=0 but freelist=%d in dtpage\n", 4413 + p->header.freelist); 4414 + return false; 4415 + } 4416 + } else { 4417 + int fsi; 4418 + 4419 + if (unlikely(p->header.freelist < 1)) { 4420 + jfs_err("Bad freelist:%d in dtpage\n", p->header.freelist); 4421 + return false; 4422 + } 4423 + 4424 + /* Traverse the free list to check validity of all node indices */ 4425 + fsi = p->header.freelist; 4426 + for (i = 0; i < p->header.freecnt - 1; i++) { 4427 + /* Check for duplicate indices in the free list */ 4428 + if (unlikely(__test_and_set_bit(fsi, bitmap))) { 4429 + jfs_err("duplicate index%d in slot in dtpage\n", fsi); 4430 + return false; 4431 + } 4432 + fsi = p->slot[fsi].next; 4433 + 4434 + /* Ensure the next slot index in the free list is valid */ 4435 + if (unlikely(fsi < 1 || fsi >= DTPAGEMAXSLOT)) { 4436 + jfs_err("Bad index:%d in slot in dtpage\n", fsi); 4437 + return false; 4438 + } 4439 + } 4440 + 4441 + /* The last node in the free list must terminate with next = -1 */ 4442 + if (unlikely(p->slot[fsi].next != -1)) { 4443 + jfs_err("Bad next:%d of the last slot in dtpage\n", 4444 + p->slot[fsi].next); 4445 + return false; 4446 + } 4447 + } 4448 + 4449 + /* stbl must be little then DTPAGEMAXSLOT */ 4450 + if (unlikely(p->header.stblindex >= DTPAGEMAXSLOT - stblsize)) { 4451 + jfs_err("Bad stblindex:%d in dtpage (stbl size %d)\n", 4452 + p->header.stblindex, stblsize); 4453 + return false; 4454 + } 4455 + 4456 + /* nextindex must be little then stblsize*32 */ 4457 + if (unlikely(p->header.nextindex > (stblsize << L2DTSLOTSIZE))) { 4458 + jfs_err("Bad nextindex:%d in dtpage (stbl size %d)\n", 4459 + p->header.nextindex, stblsize); 4460 + return false; 4461 + } 4462 + 4463 + /* Validate stbl entries 4464 + * Each entry is a slot index, valid range: -1 (invalid) or 4465 + * [0, nextindex-1] (valid data slots) 4466 + * (stblindex and higher slots are reserved for stbl itself) 4467 + */ 4468 + for (i = 0; i < p->header.nextindex; i++) { 4469 + int idx = DT_GETSTBL(p)[i]; 4470 + 4471 + /* Check if index is out of valid data slot range */ 4472 + if (unlikely(idx < 1 || idx >= DTPAGEMAXSLOT)) { 4473 + jfs_err("Bad stbl[%d] index:%d (stblindex %d) in dtpage\n", 4474 + i, idx, p->header.stblindex); 4475 + return false; 4476 + } 4477 + 4478 + /* Check for duplicate valid indices (skip -1) */ 4479 + if (unlikely(__test_and_set_bit(idx, bitmap))) { 4480 + jfs_err("Duplicate index:%d in stbl of dtpage\n", idx); 4481 + return false; 4482 + } 4483 + } 4484 + 4485 + return true; 4296 4486 }
+4
fs/jfs/jfs_dtree.h
··· 253 253 ino_t * orig_ino, ino_t new_ino, int flag); 254 254 255 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 260 #endif /* !_H_JFS_DTREE */
+4
fs/jfs/jfs_imap.c
··· 3102 3102 3103 3103 if (S_ISDIR(ip->i_mode)) { 3104 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 3109 } else if (S_ISREG(ip->i_mode) || S_ISLNK(ip->i_mode)) { 3106 3110 memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); 3107 3111 } else
+14 -20
fs/jfs/jfs_logmgr.c
··· 74 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 /* ··· 198 204 struct jfs_sb_info *sbi; 199 205 200 206 list_for_each_entry(sbi, &log->sb_list, log_list) { 201 - writer(sbi->ipbmap->i_mapping); 202 - writer(sbi->ipimap->i_mapping); 203 - writer(sbi->direct_inode->i_mapping); 207 + /* These pointers can be NULL before list_del during umount */ 208 + if (sbi->ipbmap) 209 + writer(sbi->ipbmap->i_mapping); 210 + if (sbi->ipimap) 211 + writer(sbi->ipimap->i_mapping); 212 + if (sbi->direct_inode) 213 + writer(sbi->direct_inode->i_mapping); 204 214 } 205 215 } 206 216 ··· 2178 2180 2179 2181 LCACHE_LOCK(flags); /* disable+lock */ 2180 2182 2181 - bp->l_flag |= lbmDONE; 2182 - 2183 2183 if (bio->bi_status) { 2184 2184 bp->l_flag |= lbmERROR; 2185 2185 ··· 2192 2196 if (bp->l_flag & lbmREAD) { 2193 2197 bp->l_flag &= ~lbmREAD; 2194 2198 2195 - LCACHE_UNLOCK(flags); /* unlock+enable */ 2196 - 2197 2199 /* wakeup I/O initiator */ 2198 2200 LCACHE_WAKEUP(&bp->l_ioevent); 2199 2201 2200 - return; 2202 + goto out; 2201 2203 } 2202 2204 2203 2205 /* ··· 2219 2225 2220 2226 if (bp->l_flag & lbmDIRECT) { 2221 2227 LCACHE_WAKEUP(&bp->l_ioevent); 2222 - LCACHE_UNLOCK(flags); 2223 - return; 2228 + goto out; 2224 2229 } 2225 2230 2226 2231 tail = log->wqueue; ··· 2271 2278 * leave buffer for i/o initiator to dispose 2272 2279 */ 2273 2280 if (bp->l_flag & lbmSYNC) { 2274 - LCACHE_UNLOCK(flags); /* unlock+enable */ 2275 - 2276 2281 /* wakeup I/O initiator */ 2277 2282 LCACHE_WAKEUP(&bp->l_ioevent); 2278 2283 } ··· 2281 2290 else if (bp->l_flag & lbmGC) { 2282 2291 LCACHE_UNLOCK(flags); 2283 2292 lmPostGC(bp); 2293 + LCACHE_LOCK(flags); /* disable+lock */ 2284 2294 } 2285 2295 2286 2296 /* ··· 2294 2302 assert(bp->l_flag & lbmRELEASE); 2295 2303 assert(bp->l_flag & lbmFREE); 2296 2304 lbmfree(bp); 2297 - 2298 - LCACHE_UNLOCK(flags); /* unlock+enable */ 2299 2305 } 2306 + 2307 + out: 2308 + bp->l_flag |= lbmDONE; 2309 + LCACHE_UNLOCK(flags); 2300 2310 } 2301 2311 2302 2312 int jfsIOWait(void *arg)
+7
fs/jfs/jfs_logmgr.h
··· 403 403 }; 404 404 405 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 + 412 + /* 406 413 * Log flag 407 414 */ 408 415 #define log_INLINELOG 1
+2 -1
fs/jfs/jfs_metapage.c
··· 270 270 mp->clsn = 0; 271 271 mp->log = NULL; 272 272 init_waitqueue_head(&mp->wait); 273 + INIT_LIST_HEAD(&mp->synclist); 273 274 } 274 275 return mp; 275 276 } ··· 380 379 mp->lsn = 0; 381 380 mp->clsn = 0; 382 381 log->count--; 383 - list_del(&mp->synclist); 382 + list_del_init(&mp->synclist); 384 383 } 385 384 LOGSYNC_UNLOCK(log, flags); 386 385 }
+2 -1
fs/jfs/jfs_mount.c
··· 378 378 sbi->nbperpage = PSIZE >> sbi->l2bsize; 379 379 sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; 380 380 sbi->l2niperblk = sbi->l2bsize - L2DISIZE; 381 + uuid_copy(&sbi->uuid, &j_sb->s_uuid); 382 + 381 383 if (sbi->mntflag & JFS_INLINELOG) 382 384 sbi->logpxd = j_sb->s_logpxd; 383 385 else { 384 386 sbi->logdev = new_decode_dev(le32_to_cpu(j_sb->s_logdev)); 385 - uuid_copy(&sbi->uuid, &j_sb->s_uuid); 386 387 uuid_copy(&sbi->loguuid, &j_sb->s_loguuid); 387 388 } 388 389 sbi->fsckpxd = j_sb->s_fsckpxd;
+2 -1
fs/jfs/jfs_txnmgr.c
··· 275 275 for (k = 0; k < nTxBlock; k++) { 276 276 init_waitqueue_head(&TxBlock[k].gcwait); 277 277 init_waitqueue_head(&TxBlock[k].waitor); 278 + INIT_LIST_HEAD(&TxBlock[k].synclist); 278 279 } 279 280 280 281 for (k = 1; k < nTxBlock - 1; k++) { ··· 975 974 if (tblk->lsn) { 976 975 LOGSYNC_LOCK(log, flags); 977 976 log->count--; 978 - list_del(&tblk->synclist); 977 + list_del_init(&tblk->synclist); 979 978 LOGSYNC_UNLOCK(log, flags); 980 979 } 981 980 }
+10
fs/jfs/jfs_umount.c
··· 20 20 #include "jfs_superblock.h" 21 21 #include "jfs_dmap.h" 22 22 #include "jfs_imap.h" 23 + #include "jfs_logmgr.h" 23 24 #include "jfs_metapage.h" 24 25 #include "jfs_debug.h" 25 26 ··· 59 58 jfs_flush_journal(log, 2); 60 59 61 60 /* 61 + * Hold log lock so write_special_inodes (lmLogSync) cannot see 62 + * this sbi with a NULL inode pointer while iterating log->sb_list. 63 + */ 64 + if (log) 65 + LOG_LOCK(log); 66 + /* 62 67 * close fileset inode allocation map (aka fileset inode) 63 68 */ 64 69 diUnmount(ipimap, 0); ··· 101 94 * the superblock as clean 102 95 */ 103 96 filemap_write_and_wait(sbi->direct_inode->i_mapping); 97 + 98 + if (log) 99 + LOG_UNLOCK(log); 104 100 105 101 /* 106 102 * ensure all file system file pages are propagated to their