|
14 | 14 |
|
15 | 15 | #include <errno.h> |
16 | 16 | #include <fcntl.h> |
| 17 | +#include <linux/capability.h> |
| 18 | +#include <sys/mount.h> |
17 | 19 | #include <sys/stat.h> |
18 | 20 | #include <sys/statfs.h> |
19 | 21 | #include <sys/types.h> |
|
31 | 33 | #include "test/util/cleanup.h" |
32 | 34 | #include "test/util/file_descriptor.h" |
33 | 35 | #include "test/util/fs_util.h" |
| 36 | +#include "test/util/linux_capability_util.h" |
| 37 | +#include "test/util/posix_error.h" |
34 | 38 | #include "test/util/save_util.h" |
35 | 39 | #include "test/util/temp_path.h" |
36 | 40 | #include "test/util/test_util.h" |
@@ -680,6 +684,10 @@ TEST(SimpleStatTest, AnonDeviceAllocatesUniqueInodesAcrossSaveRestore) { |
680 | 684 | #define STATX_ALL 0x00000fffU |
681 | 685 | #endif // STATX_ALL |
682 | 686 |
|
| 687 | +#ifndef STATX_MNT_ID |
| 688 | +#define STATX_MNT_ID 0x00001000U |
| 689 | +#endif // STATX_MNT_ID |
| 690 | + |
683 | 691 | // struct kernel_statx_timestamp is a Linux statx_timestamp struct. |
684 | 692 | struct kernel_statx_timestamp { |
685 | 693 | int64_t tv_sec; |
@@ -710,6 +718,7 @@ struct kernel_statx { |
710 | 718 | uint32_t stx_rdev_minor; |
711 | 719 | uint32_t stx_dev_major; |
712 | 720 | uint32_t stx_dev_minor; |
| 721 | + uint64_t stx_mnt_id; |
713 | 722 | uint64_t __spare2[14]; |
714 | 723 | }; |
715 | 724 |
|
@@ -835,6 +844,53 @@ TEST_F(StatTest, StatIgnoreNoAutomount) { |
835 | 844 | SyscallSucceeds()); |
836 | 845 | } |
837 | 846 |
|
| 847 | +TEST_F(StatTest, StatxMntId) { |
| 848 | + SKIP_IF(!IsRunningOnGvisor() && statx(-1, nullptr, 0, 0, nullptr) < 0 && |
| 849 | + errno == ENOSYS); |
| 850 | + |
| 851 | + struct kernel_statx stx; |
| 852 | + EXPECT_THAT(statx(AT_FDCWD, test_file_name_.c_str(), 0, STATX_MNT_ID, &stx), |
| 853 | + SyscallSucceeds()); |
| 854 | + EXPECT_TRUE(stx.stx_mask & STATX_MNT_ID); |
| 855 | + EXPECT_NE(stx.stx_mnt_id, 0); |
| 856 | + |
| 857 | + // Check that two files in the same mount have the same mount ID. |
| 858 | + TempPath file2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); |
| 859 | + struct kernel_statx stx2; |
| 860 | + EXPECT_THAT(statx(AT_FDCWD, file2.path().c_str(), 0, STATX_MNT_ID, &stx2), |
| 861 | + SyscallSucceeds()); |
| 862 | + EXPECT_TRUE(stx2.stx_mask & STATX_MNT_ID); |
| 863 | + EXPECT_EQ(stx.stx_mnt_id, stx2.stx_mnt_id); |
| 864 | +} |
| 865 | + |
| 866 | +TEST_F(StatTest, StatxMntIdBindMount) { |
| 867 | + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); |
| 868 | + SKIP_IF(!IsRunningOnGvisor() && statx(-1, nullptr, 0, 0, nullptr) < 0 && |
| 869 | + errno == ENOSYS); |
| 870 | + |
| 871 | + TempPath dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); |
| 872 | + TempPath dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); |
| 873 | + |
| 874 | + struct kernel_statx stx1; |
| 875 | + EXPECT_THAT(statx(AT_FDCWD, dir1.path().c_str(), 0, STATX_MNT_ID, &stx1), |
| 876 | + SyscallSucceeds()); |
| 877 | + |
| 878 | + ASSERT_THAT(mount(dir1.path().c_str(), dir2.path().c_str(), nullptr, MS_BIND, |
| 879 | + nullptr), |
| 880 | + SyscallSucceeds()); |
| 881 | + auto cleanup = Cleanup([&dir2]() { |
| 882 | + ASSERT_THAT(umount(dir2.path().c_str()), SyscallSucceeds()); |
| 883 | + }); |
| 884 | + |
| 885 | + struct kernel_statx stx2; |
| 886 | + EXPECT_THAT(statx(AT_FDCWD, dir2.path().c_str(), 0, STATX_MNT_ID, &stx2), |
| 887 | + SyscallSucceeds()); |
| 888 | + |
| 889 | + EXPECT_TRUE(stx1.stx_mask & STATX_MNT_ID); |
| 890 | + EXPECT_TRUE(stx2.stx_mask & STATX_MNT_ID); |
| 891 | + EXPECT_NE(stx1.stx_mnt_id, stx2.stx_mnt_id); |
| 892 | +} |
| 893 | + |
838 | 894 | } // namespace |
839 | 895 |
|
840 | 896 | } // namespace testing |
|
0 commit comments