return 1;
}
-static int add_clean(struct fs *fs, unsigned int dev, u32 seg)
+static int add_clean(struct fs *fs, unsigned int dev, u32 seg, bool if_present)
{
/* This dev/seg is now clean. Make sure it is on the list.
* Chances are that this is already present in the table as
- * a recently cleaned segment.
+ * a recently cleaned segment. If 'if_present', then insist
+ * on this.
* Return TRUE if segment was added to the table (as this
* implies a reference count).
*/
spin_unlock(&fs->lock);
return 0;
}
+ if (if_present) {
+ spin_unlock(&fs->lock);
+ return 0;
+ }
if (fs->segtrack->free.cnt + fs->segtrack->clean.cnt >=
fs->segtrack->total / 2) {
if (ss->usage == 0) {
int rv;
spin_unlock(&fs->lock);
- rv = add_clean(fs, ss->dev, ss->segment);
- /* FIXME we dropped the lock, so maybe this could bug?? */
- /* I should make sure I hold the block references */
- BUG_ON(rv);
+ rv = add_clean(fs, *dev, *seg, true);
+ BUG_ON(rv); /* passing 'true' makes this impossible */
goto retry;
}
segdelete(fs->segtrack, ss);
fs->total_free += segsize - usage /* - 1 */;
if (usage == 0) {
- int rv = add_clean(fs, dev, seg);
+ int rv = add_clean(fs, dev, seg, false);
lafs_check_seg_cnt(fs->segtrack);
return rv;
}