Looks like each time you remove one, you then start again at the very beginning of the list in your search for the next one, and you will examine the same nodes over and over again.
Don't do that.
Your remove_first function could provide to the caller the node after the one that was removed, and could accept a node to beging searching at. Then, each time remove_first returns, you call it again with that start position node value so you don't start at the beginning of the list again.