lafs_write_state(fs);
dprintk("State written, all done %d\n", fs->seq);
- if (!test_bit(CleanerDisabled, &fs->fsstate))
+ if (!test_bit(CleanerDisabled, &fs->fsstate)) {
fs->scan.done = 0;
+ if (youth > 65536 - 2 * fs->max_newsegs) {
+ /* time to decay youth */
+ spin_lock(&fs->lock);
+ youth = decay_youth(youth);
+ fs->youth_next = decay_youth(fs->youth_next);
+ fs->scan.do_decay = 1;
+ spin_unlock(&fs->lock);
+ }
+ }
fs->cleaner.cleaning = 0;
fs->checkpoint_youth = youth;
if (!test_bit(CheckpointNeeded, &fs->fsstate))
return MAX_SCHEDULE_TIMEOUT;
- if (fs->cleaner.active)
+ if (fs->cleaner.active || ! fs->scan.done)
return HZ/10; /* FIXME that is gross ... is it needed? */
/* Make sure all cleaner blocks are flushed as if anything lingers
}
if (db) {
+ u16 y = fs->youth_next;
+ if (fs->scan.do_decay &&
+ (fs->scan.free_dev < ss->dev
+ || (fs->scan.free_dev == ss->dev
+ && fs->scan.free_block < (ss->segment
+ / (fs->blocksize / 2)))
+ ))
+ /* Haven't decayed this block yet - revert decay */
+ y = decay_undo(y);
youthp = map_dblock(db);
youthp[(*seg) & ((1 << (fs->blocksize_bits
- 1)) - 1)]
- = fs->youth_next;
+ = cpu_to_le16(y);
unmap_dblock(db, youthp);
}
fs->youth_next++;
dprintk("scan: dev=%d block=%d stage=%d\n",
fs->scan.free_dev, fs->scan.free_block, fs->scan.free_stage);
if (fs->scan.free_stage == 0) {
- /* Need to find the youth block for this dev/offset.
+ /* Need to find the youth block for next dev/offset.
* Possibly we are finished with this dev and must go
* to next. Possibly we are finished altogether.
*/
+ int dev = fs->scan.free_dev;
+ int block = fs->scan.free_block + 1;
+ int err;
- while (fs->scan.free_block >
- (fs->devs[fs->scan.free_dev].segment_count
- >> (fs->blocksize_bits - 1))) {
- fs->scan.free_dev++;
- fs->scan.free_block = 0;
- if (fs->scan.free_dev >= fs->devices) {
- fs->scan.free_dev = 0;
- fs->scan.done = 1;
+ while (dev < 0 ||
+ block > (fs->devs[dev].segment_count
+ >> (fs->blocksize_bits - 1))) {
+ dev++;
+ block = 0;
+ if (dev >= fs->devices) {
+ fs->scan.free_dev = -1;
+ dev = -1;
+ fs->scan.do_decay = 0;
fs->scan.trace = 0;
fs->total_free_prev = fs->total_free;
fs->total_free = 0;
fs->scan.first_free_pass = 0;
- wake_up(&fs->phase_wait);
- return MAX_SCHEDULE_TIMEOUT;
+ break;
}
}
+ if (fs->scan.youth_db)
+ if (fs->scan.youth_db->b.fileaddr != block ||
+ dev < 0 ||
+ fs->scan.youth_db->b.inode != fs->devs[dev].segsum) {
+ putdref(fs->scan.youth_db, MKREF(youth_scan));
+ fs->scan.youth_db = NULL;
+ }
+ if (dev == -1) {
+ fs->scan.done = 1;
+ wake_up(&fs->phase_wait);
+ return MAX_SCHEDULE_TIMEOUT;
+ }
+
if (fs->scan.youth_db == NULL)
fs->scan.youth_db =
- lafs_get_block(fs->devs[fs->scan.free_dev]
- .segsum,
- fs->scan.free_block,
- NULL, GFP_KERNEL, MKREF(youth));
+ lafs_get_block(fs->devs[dev].segsum,
+ block,
+ NULL, GFP_KERNEL, MKREF(youth_scan));
if (!fs->scan.youth_db) {
printk("EEEEEKKKKK get_block failed\n");
- fs->scan.free_block++;
- return 1;
- }
- switch (lafs_read_block_async(fs->scan.youth_db)) {
- default:
- case -EIO:
- printk("EEEEEKKKKK read of youth block failed\n");
- putdref(fs->scan.youth_db, MKREF(youth));
- fs->scan.youth_db = NULL;
- fs->scan.free_block++;
- return 1;
- case -EAGAIN:
return MAX_SCHEDULE_TIMEOUT;
- case 0:
- break;
+ } else
+ switch (err = lafs_read_block_async(fs->scan.youth_db)) {
+ default:
+ case -EIO:
+ printk("EEEEEKKKKK read of youth block failed\n");
+ break;
+ case -EAGAIN:
+ return MAX_SCHEDULE_TIMEOUT;
+ case 0:
+ break;
+ }
+
+ if (fs->scan.do_decay) {
+ /* youth_db must be writable */
+ struct datablock *db = fs->scan.youth_db;
+ lafs_checkpoint_lock(fs);
+ set_bit(B_PinPending, &db->b.flags);
+ lafs_pin_dblock(db, AccountSpace);
}
+ spin_lock(&fs->lock);
+ fs->scan.free_block = block;
+ fs->scan.free_dev = dev;
+ if (!err && fs->scan.do_decay) {
+ u16 *yp = map_dblock(fs->scan.youth_db);
+ int i;
+ int segperblk = fs->blocksize / 2;
+
+ for (i = 0 ; i < segperblk ; i++) {
+ int y = le16_to_cpu(yp[i]);
+ if (y >= 8)
+ y = decay_youth(y);
+ }
+ unmap_dblock(fs->scan.youth_db, yp);
+ lafs_dirty_dblock(fs->scan.youth_db);
+ }
+ spin_unlock(&fs->lock);
+ if (fs->scan.do_decay)
+ lafs_checkpoint_unlock(fs);
+ if (err)
+ return 1;
fs->scan.free_stage = 1;
}
WARN_ON(lafs_check_seg_cnt(fs->segtrack));
if (!db) {
printk("EEEEKKK get_block for first usage failed\n");
abort:
- fs->scan.free_block++;
fs->scan.free_stage = 0;
- putdref(fs->scan.youth_db, MKREF(youth));
- fs->scan.youth_db = NULL;
return 1;
}
switch (lafs_read_block_async(db)) {
if (!db) {
printk("EEEEKKK get_block for subsequent usage failed\n");
abort2:
- fs->scan.free_block++;
fs->scan.free_stage = 0;
- putdref(fs->scan.youth_db, MKREF(youth));
- fs->scan.youth_db = NULL;
putdref(fs->scan.usage0_db, MKREF(usage0));
fs->scan.usage0_db = NULL;
return 1;
}
unmap_dblock(fs->scan.youth_db, yp);
- putdref(fs->scan.youth_db, MKREF(youth));
- fs->scan.youth_db = NULL;
putdref(fs->scan.usage0_db, MKREF(usage0));
fs->scan.usage0_db = NULL;
- fs->scan.free_block++;
fs->scan.free_stage = 0;
}
WARN_ON(lafs_check_seg_cnt(fs->segtrack));
if (fs->scan.trace)
return HZ/10;
+ else if (fs->scan.free_stage == 0)
+ return 1;
else
return MAX_SCHEDULE_TIMEOUT;
}