Skip to content

Linux: always check or verify return of igrab() #11704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 16, 2021

Conversation

adamdmoss
Copy link
Contributor

@adamdmoss adamdmoss commented Mar 7, 2021

Motivation and Context

zhold() wraps Linux's igrab(); igrab() and zhold() are used in several places in ZFS where they are expected to succeed, with an eventual symmetric zrele()/iput(). However, if the inode is already in the process of being deleted then igrab() can fail and return NULL; in this case a reference is not created on the inode and it a bug to subsequently iput() it (possible premature recycling of the inode memory leading to hard-to-diagnose issues).

Description

How Has This Been Tested?

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Performance enhancement (non-breaking change which improves efficiency)
  • Code cleanup (non-breaking change which makes code smaller or more readable)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Library ABI change (libzfs, libzfs_core, libnvpair, libuutil and libzfsbootenv)
  • Documentation (a change to man pages or other documentation)

Checklist:

@behlendorf behlendorf added the Status: Work in Progress Not yet ready for general review label Mar 8, 2021
@behlendorf
Copy link
Contributor

Thanks for improving this bit of the code. In general the original undocumented rational for not checking for NULL when using zhold() is that it was only called when the inode was already known to have a reference. In which case it couldn't fail, because the first existing reference would ensure it was never in the process of being deleted. This is always going to be the case for any Linux VFS callback we register which passes us a dentry or an inode. The main place where this is a concern is in zfs_zget() where we might be getting the first reference, and therefore we do need to check for NULL.

I agree we should really make this all much more clear. A reasonable approach might be to add a VERIFY() and a short comment for the cases where we know there must already be a reference. Then add NULL checks as you've done if there are any places left where this may not be true.

@adamdmoss
Copy link
Contributor Author

I honestly can't tell which cases know there's already a ref vs those which don't; should I assume that all the existing code is correct and just VERIFY() that?

Should I make the same assumption that igrab() is always being used where there's already a ref, as well as zhold()?

@behlendorf
Copy link
Contributor

It's definitely not very clear. But I believe it's the case that we're checking the igrab() return value everywhere we should be and it would be safe to wrap them all in a VERIFY(). If that's not the case, this would be a good way to find out!

A good example of a place where we know we must have a reference, and it's not currently checked, would be the igrab() in zpl_link(). This is the zpl_dir_inode_operations->link() callback registered with the Linux VFS and it is passed the old_dentry as an argument from which we get the inode. This dentry must have a reference on the inode it points to so we know the igrab() here cannot fail. This will be the case for any of registered VFS callbacks, most (maybe all?) of which pass us a dentry or an inode which will have a reference held by the VFS caller.

@adamdmoss
Copy link
Contributor Author

Is this version more what you had in mind?

@adamdmoss adamdmoss marked this pull request as ready for review March 8, 2021 23:07
@adamdmoss adamdmoss changed the title WIP: always check return of zhold() and igrab(), enforce check of return w/gcc Always check return of zhold() and igrab(), enforce check of return w/gcc Mar 8, 2021
Copy link
Contributor

@behlendorf behlendorf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, think this is preferable since it makes it clear why it can never be NULL.

@adamdmoss adamdmoss changed the title Always check return of zhold() and igrab(), enforce check of return w/gcc Always check return of zhold() and igrab(), enforce check of retur Mar 9, 2021
@adamdmoss adamdmoss changed the title Always check return of zhold() and igrab(), enforce check of retur Always check return of zhold() and igrab(), enforce check of return Mar 9, 2021
@adamdmoss adamdmoss changed the title Always check return of zhold() and igrab(), enforce check of return (Linux) - VERIFY() return of igrab() where otherwise unchecked Mar 11, 2021
@adamdmoss
Copy link
Contributor Author

I think this is done now.

@behlendorf
Copy link
Contributor

Functionally this looks good to me, could you just address the style comments about lines over 80 characters. You can run make cstyle locally to check for style issues. I think you could also convert those those igrab()s where you added a verify to just use the updated zhold() wrapper.

@behlendorf behlendorf added Status: Code Review Needed Ready for review and testing and removed Status: Work in Progress Not yet ready for general review labels Mar 12, 2021
@adamdmoss
Copy link
Contributor Author

Oh... yes... sorry, forgot about checkstyle.

Copy link
Contributor

@behlendorf behlendorf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@adamdmoss adamdmoss changed the title (Linux) - VERIFY() return of igrab() where otherwise unchecked Linux: always check or verify return of igrab() Mar 12, 2021
@adamdmoss
Copy link
Contributor Author

Hi @behlendorf is this waiting on anything more from me? Thanks.

@behlendorf
Copy link
Contributor

@adamdmoss no this one was just blocked on me to circle back to merge it. Although more review is always welcome! I'll go ahead and merge it now. Thanks!

@behlendorf behlendorf added Status: Accepted Ready to integrate (reviewed, tested) and removed Status: Code Review Needed Ready for review and testing labels Mar 16, 2021
@behlendorf behlendorf merged commit 1daad98 into openzfs:master Mar 16, 2021
jsai20 pushed a commit to jsai20/zfs that referenced this pull request Mar 30, 2021
zhold() wraps igrab() on Linux, and igrab() may fail when the inode 
is in the process of being deleted.  This means zhold() must only be
called when a reference exists and therefore it cannot be deleted. 
This is the case for all existing consumers so add a VERIFY and a
comment explaining this requirement.

Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Adam Moss <[email protected]>
Closes openzfs#11704
adamdmoss added a commit to adamdmoss/zfs that referenced this pull request Apr 10, 2021
zhold() wraps igrab() on Linux, and igrab() may fail when the inode 
is in the process of being deleted.  This means zhold() must only be
called when a reference exists and therefore it cannot be deleted. 
This is the case for all existing consumers so add a VERIFY and a
comment explaining this requirement.

Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Adam Moss <[email protected]>
Closes openzfs#11704
sempervictus pushed a commit to sempervictus/zfs that referenced this pull request May 31, 2021
zhold() wraps igrab() on Linux, and igrab() may fail when the inode 
is in the process of being deleted.  This means zhold() must only be
called when a reference exists and therefore it cannot be deleted. 
This is the case for all existing consumers so add a VERIFY and a
comment explaining this requirement.

Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Adam Moss <[email protected]>
Closes openzfs#11704
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jun 4, 2021
zhold() wraps igrab() on Linux, and igrab() may fail when the inode 
is in the process of being deleted.  This means zhold() must only be
called when a reference exists and therefore it cannot be deleted. 
This is the case for all existing consumers so add a VERIFY and a
comment explaining this requirement.

Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Adam Moss <[email protected]>
Closes openzfs#11704
tonyhutter pushed a commit that referenced this pull request Jun 23, 2021
zhold() wraps igrab() on Linux, and igrab() may fail when the inode 
is in the process of being deleted.  This means zhold() must only be
called when a reference exists and therefore it cannot be deleted. 
This is the case for all existing consumers so add a VERIFY and a
comment explaining this requirement.

Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Adam Moss <[email protected]>
Closes #11704
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Accepted Ready to integrate (reviewed, tested)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants