om->nextfree--;
om->reserved++;
clear_bit(B_Orphan, &b->b.flags);
- /* NOTE we don't remove the block from the orphan
- * list yet. This allows lafs_run_orphans to keep
- * track of the current location in the list.
- * Any other called of handle_orphan must call
- * drop_orphan afterwards.
- * so don't: list_del_init(&b->orphans);
- * and don't: putdref(b, MKREF(orphan_list));
- */
+ lafs_drop_orphan(fs, b);
/* Now drop the reservation we just synthesised */
orphan_abort(fs);
long lafs_run_orphans(struct fs *fs)
{
- struct datablock *db, *next, *toput = NULL;
+ struct datablock *db;
+ struct list_head done;
+ if (list_empty_careful(&fs->pending_orphans))
+ return MAX_SCHEDULE_TIMEOUT;
+
+ INIT_LIST_HEAD(&done);
+ /* Now process the orphans. Move each one to 'done',
+ * then handle it. Those which remain on 'done' get
+ * moved back at the end.
+ */
spin_lock(&fs->lock);
- list_for_each_entry_safe(db, next, &fs->pending_orphans, orphans) {
- struct mutex *mx = orphan_mutex(db);
+ while (!list_empty(&fs->pending_orphans)) {
+ struct mutex *mx;
+ db = list_entry(fs->pending_orphans.next,
+ struct datablock,
+ orphans);
+ list_move(&db->orphans, &done);
+ mx = orphan_mutex(db);
if (!mx || !mutex_trylock(mx))
continue;
spin_unlock(&fs->lock);
* while we own the mutex, so our reference to db is safe
*/
- if (toput) {
- putdref(toput, MKREF(orphan_list));
- toput = NULL;
- }
switch(LAFSI(db->b.inode)->type) {
case TypeInodeFile:
lafs_inode_handle_orphan(db);
lafs_dir_handle_orphan(db);
break;
}
+ mutex_unlock(mx);
- spin_lock(&fs->lock);
- /* the 'next' entry might have been deleted, so
- * get the current value. 'db' cannot have been removed
- * from the list as we held the mutex.
+ /* The block has either been put, or is still on
+ * 'done'.
*/
- mutex_unlock(mx);
- next = list_entry(db->orphans.next, struct datablock,
- orphans);
- if (!test_bit(B_Orphan, &db->b.flags)) {
- list_del_init(&db->orphans);
- toput = db;
- }
+ spin_lock(&fs->lock);
}
+ list_splice(&done, &fs->pending_orphans);
spin_unlock(&fs->lock);
- if (toput)
- putdref(toput, MKREF(orphan_list));
+
if (list_empty(&fs->pending_orphans))
/* unmount might be waiting... */
wake_up(&fs->async_complete);