On Thu, Oct 03, 2024 at 01:45:55PM +0200, Jan Kara wrote: > /* Find next inode on the inode list eligible for processing */ > #define sb_inode_iter_next(sb, inode, old_inode, inode_eligible) \ > ({ \ > struct inode *ret = NULL; \ <snip> > ret; \ > }) How is this going to interact with calling into the file system to do the interaction, which is kinda the point of this series? Sure, you could have a get_next_inode-style method, but it would need a fair amount of entirely file system specific state that needs to be stashed away somewhere, and all options for that looks pretty ugly. Also even with your pre-iget callback we'd at best halve the number of indirect calls for something that isn't exactly performance critical. So while it could be done that way, it feels like a more complex and much harder to reason about version for no real benefit. > #define for_each_sb_inode(sb, inode, inode_eligible) \ > for (DEFINE_FREE(old_inode, struct inode *, if (_T) iput(_T)), \ > inode = NULL; \ > inode = sb_inode_iter_next((sb), inode, &old_inode, \ > inode_eligible); \ > ) And while I liked: obj = NULL; while ((obj = get_next_object(foo, obj))) { } style iterators, magic for_each macros that do magic cleanup are just a nightmare to read. Keep it simple and optimize for someone actually having to read and understand the code, and not for saving a few lines of code.