NVSL / linux-nova

NOVA is a log-structured file system designed for byte-addressable non-volatile memories, developed at the University of California, San Diego.
http://nvsl.ucsd.edu/index.php?path=projects/nova
Other
422 stars 117 forks source link

Read Fault when init inode list from inode in case of a crash #146

Open iaoing opened 6 months ago

iaoing commented 6 months ago

Issue

In the function nova_init_inode_list_from_inode, struct nova_inode_info_header sih is not zero-out, leading to Read Fault in nova_free_inode_log due to the memory copy from the primary inode to the alternative inode (invalid address). On the contrary, in the function nova_init_blockmap_from_inode, sih is zero-out correctly and won't cause this issue.

Reproduce

Theoretically, umounting NOVA and then remounting it will trigger this issue due to the normal recovery. However, it depends on whether sih is already zero-out when allocated on the stack. In my tests, the remount after a fully umounting does not trigger this bug. It can only be triggered if the system crashes when blocknode's log_head and log_tail is set (at Line 532 and 533 as the below code snippet shows). If log_head and log_tail is not set, NOVA will go to the failure recovery and does not init inode list from inode. Indeed, after Line 533, no other metadata/data will be persisted to the PM device. Have no idea why the crash leads to garbage numbers in sih.

https://github.com/NVSL/linux-nova/blob/976a4d1f3d5282863b23aa834e02012167be6ee2/fs/nova/bbuild.c#L529-L535

Reason

https://github.com/NVSL/linux-nova/blob/976a4d1f3d5282863b23aa834e02012167be6ee2/fs/nova/bbuild.c#L283-L362

In this function, nova_init_inode_list_from_inode, sih is declared at Line 287 without zeroout. Then, sih is used to free logs when calling nova_free_inode_log at Line 360.

https://github.com/NVSL/linux-nova/blob/976a4d1f3d5282863b23aa834e02012167be6ee2/fs/nova/log.c#L1409-L1446

In this function, nova_free_inode_log, alter_pi will be synced with the primary inode, at Line 1428-1435, leading to Read Fault if alter_pi has the garbage number.

https://github.com/NVSL/linux-nova/blob/976a4d1f3d5282863b23aa834e02012167be6ee2/fs/nova/bbuild.c#L196-L210

In this function, nova_init_blockmap_from_inode, on the contrary, sih is zeroed out at Line 209. Thus, it won't cause Read Fault when freeing logs since if (alter_pi) is false (at Line 1431 in nova_free_inode_log).

Fix

Zeroing out sih, so that the synchronization between the primary inode and the alternative inode won't be triggered since if (alter_pi) is false (at Line 1431 in nova_free_inode_log).

// zero out sih at Line 298 in function `nova_init_inode_list_from_inode`.
memset(&sih, 0, sizeof(struct nova_inode_info_header));