-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
segfault when using rollback while doing dd #795
Comments
Thanks for the reproducer it should make it easier to run down. |
The following procedure reliably reproduces a variation of this bug for me. I'm not sure if rolling back a mounted filesystem is even supposed to work. The old Solaris ZFS administration guide says a mounted filesystem is unmounted and remounted, and the rollback fails if the unmount fails. However the current code doesn't seem to attempt this, so that documentation may be obsolete. Also, I verified that this test works on Open Indiana, so there may be a reasonable way to fix this on Linux.
The last touch triggers a WARNING and GPF then segfaults:
The WARN from
Regarding the GPF, zfs_inode_destroy+0x9e resolves to Finally, I've determined that
where |
Rolling back a mounted filesystem with open file handles and cached dentries+inodes never worked properly in ZoL. The major issue was that Linux provides no easy mechanism for modules to invalidate the inode cache for a file system. Because of this it was possible that an inode from the previous filesystem would not get properly dropped from the cache during rolling back. Then a new inode with the same inode number would be create and collide with the existing cached inode. Ideally this would trigger an VERIFY() but in practice the error wasn't handled and it would just NULL reference. Luckily, this issue can be resolved by sprucing up the existing Solaris zfs_rezget() functionality for the Linux VFS. The way it works now is that when a file system is rolled back all the cached inodes will be traversed and refetched from disk. If a version of the cached inode exists on disk the in-core copy will be updated accordingly. If there is no match for that object on disk it will be unhashed from the inode cache and marked as stale. This will effectively make the inode unfindable for lookups allowing the inode number to be immediately recycled. The inode will then only be accessible from the cached dentries. Subsequent dentry lookups which reference a stale inode will result in the dentry being invalidated. Once invalidated the dentry will drop its reference on the inode allowing it to be safely pruned from the cache. Special care is taken for negative dentries since they do not reference any inode. These dentires will be invalidate based on when they were added to the dentry cache. Entries added before the last rollback will be invalidate to prevent them from masking real files in the dataset. Two nice side effects of this fix are: * Removes the dependency on spl_invalidate_inodes(), it can now be safely removed from the SPL when we choose to do so. * zfs_znode_alloc() no longer requires a dentry to be passed. This effectively reverts this portition of the code to its upstream counterpart. The dentry is not instantiated more correctly in the Linux ZPL layer. Signed-off-by: Brian Behlendorf <[email protected]> Issue openzfs#795
This functionality is no longer required by ZFS, see commit openzfs/zfs@7b3e34b. Since there are no other consumers, and because it adds additional autoconf complexity which must be maintained the spl_invalidate_inodes() function has been removed. Signed-off-by: Brian Behlendorf <[email protected]> Issue openzfs/zfs#795
This functionality is no longer required by ZFS, see commit openzfs/zfs@7b3e34b. Since there are no other consumers, and because it adds additional autoconf complexity which must be maintained the spl_invalidate_inodes() function has been removed. Signed-off-by: Brian Behlendorf <[email protected]> Issue openzfs/zfs#795
Rolling back a mounted filesystem with open file handles and cached dentries+inodes never worked properly in ZoL. The major issue was that Linux provides no easy mechanism for modules to invalidate the inode cache for a file system. Because of this it was possible that an inode from the previous filesystem would not get properly dropped from the cache during rolling back. Then a new inode with the same inode number would be create and collide with the existing cached inode. Ideally this would trigger an VERIFY() but in practice the error wasn't handled and it would just NULL reference. Luckily, this issue can be resolved by sprucing up the existing Solaris zfs_rezget() functionality for the Linux VFS. The way it works now is that when a file system is rolled back all the cached inodes will be traversed and refetched from disk. If a version of the cached inode exists on disk the in-core copy will be updated accordingly. If there is no match for that object on disk it will be unhashed from the inode cache and marked as stale. This will effectively make the inode unfindable for lookups allowing the inode number to be immediately recycled. The inode will then only be accessible from the cached dentries. Subsequent dentry lookups which reference a stale inode will result in the dentry being invalidated. Once invalidated the dentry will drop its reference on the inode allowing it to be safely pruned from the cache. Special care is taken for negative dentries since they do not reference any inode. These dentires will be invalidate based on when they were added to the dentry cache. Entries added before the last rollback will be invalidate to prevent them from masking real files in the dataset. Two nice side effects of this fix are: * Removes the dependency on spl_invalidate_inodes(), it can now be safely removed from the SPL when we choose to do so. * zfs_znode_alloc() no longer requires a dentry to be passed. This effectively reverts this portition of the code to its upstream counterpart. The dentry is not instantiated more correctly in the Linux ZPL layer. Signed-off-by: Brian Behlendorf <[email protected]> Signed-off-by: Ned Bass <[email protected]> Closes openzfs#795
Blocks are ingested to the zettacache in 2 cases: * when writing a new object, we add all its blocks to the zettacache * when reading a block which is not in the zettacache, we get the object and add all its (not-already-present) blocks to the zettacache In both cases, we are adding many blocks (up to ~300) that are part of the same object. The current code mostly handles each block individually, causing repeated work, especially to lock and unlock various data structures. This commit streamlines the batch insertion of all the (not-already-present) blocks in object. There are 3 main aspects to this: * bulk lookup: `zettacache::Inner::lookup_all_impl()` takes a list of keys and executes a callback for each of them, providing the IndexValue. The Locked lock is obtained at most twice. * bulk insert: `zettacache::Inner::insert_all_impl()` takes a list of keys and buffers, and writes all of them to disk. The Locked lock is obtained once. * bulk LockedKey: the new `RangeLock` is used to lock the range of keys covered by the object. Only one lock is obtained for the object, instead of one lock from the LockSet for each block. The performance of ingesting via reading random blocks is improved by 100-200% (performance is 2-3x what is was before).
System:
ZFS and SPL versions: 0.6.0_rc9
How to model this situation(it happens not every times, but very often):
dd if=/dev/zero of=/zerofile bs=1M
zfs rollback bledge/root@create_test_sh
dd interrupts with input/output error, but i think it is ok for this situation...
Second terminal:
First terminal:
After that, any command in already opened terminal stucks that terminal, only reboot helps...
The text was updated successfully, but these errors were encountered: