@@ -33,15 +33,24 @@ static const char *const known_fs[] = {
3333 "sysv" , "tmpfs" , "tracefs" , "ubifs" , "udf" , "ufs" , "v7" , "vboxsf" ,
3434 "vfat" , "virtiofs" , "vxfs" , "xenfs" , "xfs" , "zonefs" , NULL };
3535
36- static struct statmount * statmount_alloc (uint64_t mnt_id , uint64_t mask , unsigned int flags )
36+ static struct statmount * statmount_alloc (uint64_t mnt_id , int fd , uint64_t mask , unsigned int flags )
3737{
3838 size_t bufsize = 1 << 15 ;
39- struct statmount * buf = NULL , * tmp = alloca ( bufsize ) ;
39+ struct statmount * buf = NULL , * tmp = NULL ;
4040 int tofree = 0 ;
4141 int ret ;
4242
43+ if (flags & STATMOUNT_BY_FD && fd < 0 )
44+ return NULL ;
45+
46+ tmp = alloca (bufsize );
47+
4348 for (;;) {
44- ret = statmount (mnt_id , 0 , mask , tmp , bufsize , flags );
49+ if (flags & STATMOUNT_BY_FD )
50+ ret = statmount (0 , 0 , (uint32_t ) fd , mask , tmp , bufsize , flags );
51+ else
52+ ret = statmount (mnt_id , 0 , 0 , mask , tmp , bufsize , flags );
53+
4554 if (ret != -1 )
4655 break ;
4756 if (tofree )
@@ -237,7 +246,7 @@ static void test_statmount_zero_mask(void)
237246 struct statmount sm ;
238247 int ret ;
239248
240- ret = statmount (root_id , 0 , 0 , & sm , sizeof (sm ), 0 );
249+ ret = statmount (root_id , 0 , 0 , 0 , & sm , sizeof (sm ), 0 );
241250 if (ret == -1 ) {
242251 ksft_test_result_fail ("statmount zero mask: %s\n" ,
243252 strerror (errno ));
@@ -263,7 +272,7 @@ static void test_statmount_mnt_basic(void)
263272 int ret ;
264273 uint64_t mask = STATMOUNT_MNT_BASIC ;
265274
266- ret = statmount (root_id , 0 , mask , & sm , sizeof (sm ), 0 );
275+ ret = statmount (root_id , 0 , 0 , mask , & sm , sizeof (sm ), 0 );
267276 if (ret == -1 ) {
268277 ksft_test_result_fail ("statmount mnt basic: %s\n" ,
269278 strerror (errno ));
@@ -323,7 +332,7 @@ static void test_statmount_sb_basic(void)
323332 struct statx sx ;
324333 struct statfs sf ;
325334
326- ret = statmount (root_id , 0 , mask , & sm , sizeof (sm ), 0 );
335+ ret = statmount (root_id , 0 , 0 , mask , & sm , sizeof (sm ), 0 );
327336 if (ret == -1 ) {
328337 ksft_test_result_fail ("statmount sb basic: %s\n" ,
329338 strerror (errno ));
@@ -375,7 +384,7 @@ static void test_statmount_mnt_point(void)
375384{
376385 struct statmount * sm ;
377386
378- sm = statmount_alloc (root_id , STATMOUNT_MNT_POINT , 0 );
387+ sm = statmount_alloc (root_id , 0 , STATMOUNT_MNT_POINT , 0 );
379388 if (!sm ) {
380389 ksft_test_result_fail ("statmount mount point: %s\n" ,
381390 strerror (errno ));
@@ -405,7 +414,7 @@ static void test_statmount_mnt_root(void)
405414 assert (last_dir );
406415 last_dir ++ ;
407416
408- sm = statmount_alloc (root_id , STATMOUNT_MNT_ROOT , 0 );
417+ sm = statmount_alloc (root_id , 0 , STATMOUNT_MNT_ROOT , 0 );
409418 if (!sm ) {
410419 ksft_test_result_fail ("statmount mount root: %s\n" ,
411420 strerror (errno ));
@@ -438,7 +447,7 @@ static void test_statmount_fs_type(void)
438447 const char * fs_type ;
439448 const char * const * s ;
440449
441- sm = statmount_alloc (root_id , STATMOUNT_FS_TYPE , 0 );
450+ sm = statmount_alloc (root_id , 0 , STATMOUNT_FS_TYPE , 0 );
442451 if (!sm ) {
443452 ksft_test_result_fail ("statmount fs type: %s\n" ,
444453 strerror (errno ));
@@ -467,7 +476,7 @@ static void test_statmount_mnt_opts(void)
467476 char * line = NULL ;
468477 size_t len = 0 ;
469478
470- sm = statmount_alloc (root_id , STATMOUNT_MNT_BASIC | STATMOUNT_MNT_OPTS ,
479+ sm = statmount_alloc (root_id , 0 , STATMOUNT_MNT_BASIC | STATMOUNT_MNT_OPTS ,
471480 0 );
472481 if (!sm ) {
473482 ksft_test_result_fail ("statmount mnt opts: %s\n" ,
@@ -557,7 +566,7 @@ static void test_statmount_string(uint64_t mask, size_t off, const char *name)
557566 uint32_t start , i ;
558567 int ret ;
559568
560- sm = statmount_alloc (root_id , mask , 0 );
569+ sm = statmount_alloc (root_id , 0 , mask , 0 );
561570 if (!sm ) {
562571 ksft_test_result_fail ("statmount %s: %s\n" , name ,
563572 strerror (errno ));
@@ -586,14 +595,14 @@ static void test_statmount_string(uint64_t mask, size_t off, const char *name)
586595 exactsize = sm -> size ;
587596 shortsize = sizeof (* sm ) + i ;
588597
589- ret = statmount (root_id , 0 , mask , sm , exactsize , 0 );
598+ ret = statmount (root_id , 0 , 0 , mask , sm , exactsize , 0 );
590599 if (ret == -1 ) {
591600 ksft_test_result_fail ("statmount exact size: %s\n" ,
592601 strerror (errno ));
593602 goto out ;
594603 }
595604 errno = 0 ;
596- ret = statmount (root_id , 0 , mask , sm , shortsize , 0 );
605+ ret = statmount (root_id , 0 , 0 , mask , sm , shortsize , 0 );
597606 if (ret != -1 || errno != EOVERFLOW ) {
598607 ksft_test_result_fail ("should have failed with EOVERFLOW: %s\n" ,
599608 strerror (errno ));
@@ -658,6 +667,226 @@ static void test_listmount_tree(void)
658667 ksft_test_result_pass ("listmount tree\n" );
659668}
660669
670+ static void test_statmount_by_fd (void )
671+ {
672+ struct statmount * sm = NULL ;
673+ char tmpdir [] = "/statmount.fd.XXXXXX" ;
674+ const char root [] = "/test" ;
675+ char subdir [PATH_MAX ], tmproot [PATH_MAX ];
676+ int fd ;
677+
678+ if (!mkdtemp (tmpdir )) {
679+ ksft_perror ("mkdtemp" );
680+ return ;
681+ }
682+
683+ if (mount ("statmount.test" , tmpdir , "tmpfs" , 0 , NULL )) {
684+ ksft_perror ("mount" );
685+ rmdir (tmpdir );
686+ return ;
687+ }
688+
689+ snprintf (subdir , PATH_MAX , "%s%s" , tmpdir , root );
690+ snprintf (tmproot , PATH_MAX , "%s/%s" , tmpdir , "chroot" );
691+
692+ if (mkdir (subdir , 0755 )) {
693+ ksft_perror ("mkdir" );
694+ goto err_tmpdir ;
695+ }
696+
697+ if (mount (subdir , subdir , NULL , MS_BIND , 0 )) {
698+ ksft_perror ("mount" );
699+ goto err_subdir ;
700+ }
701+
702+ if (mkdir (tmproot , 0755 )) {
703+ ksft_perror ("mkdir" );
704+ goto err_subdir ;
705+ }
706+
707+ fd = open (subdir , O_PATH );
708+ if (fd < 0 ) {
709+ ksft_perror ("open" );
710+ goto err_tmproot ;
711+ }
712+
713+ if (chroot (tmproot )) {
714+ ksft_perror ("chroot" );
715+ goto err_fd ;
716+ }
717+
718+ sm = statmount_alloc (0 , fd , STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT , STATMOUNT_BY_FD );
719+ if (!sm ) {
720+ ksft_test_result_fail ("statmount by fd failed: %s\n" , strerror (errno ));
721+ goto err_chroot ;
722+ }
723+
724+ if (sm -> size < sizeof (* sm )) {
725+ ksft_test_result_fail ("unexpected size: %u < %u\n" ,
726+ sm -> size , (uint32_t ) sizeof (* sm ));
727+ goto err_chroot ;
728+ }
729+
730+ if (sm -> mask & STATMOUNT_MNT_POINT ) {
731+ ksft_test_result_fail ("STATMOUNT_MNT_POINT unexpectedly set in statmount\n" );
732+ goto err_chroot ;
733+ }
734+
735+ if (!(sm -> mask & STATMOUNT_MNT_ROOT )) {
736+ ksft_test_result_fail ("STATMOUNT_MNT_ROOT not set in statmount\n" );
737+ goto err_chroot ;
738+ }
739+
740+ if (strcmp (root , sm -> str + sm -> mnt_root ) != 0 ) {
741+ ksft_test_result_fail ("statmount returned incorrect mnt_root,"
742+ "statmount mnt_root: %s != %s\n" ,
743+ sm -> str + sm -> mnt_root , root );
744+ goto err_chroot ;
745+ }
746+
747+ if (chroot ("." )) {
748+ ksft_perror ("chroot" );
749+ goto out ;
750+ }
751+
752+ free (sm );
753+ sm = statmount_alloc (0 , fd , STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT , STATMOUNT_BY_FD );
754+ if (!sm ) {
755+ ksft_test_result_fail ("statmount by fd failed: %s\n" , strerror (errno ));
756+ goto err_fd ;
757+ }
758+
759+ if (sm -> size < sizeof (* sm )) {
760+ ksft_test_result_fail ("unexpected size: %u < %u\n" ,
761+ sm -> size , (uint32_t ) sizeof (* sm ));
762+ goto out ;
763+ }
764+
765+ if (!(sm -> mask & STATMOUNT_MNT_POINT )) {
766+ ksft_test_result_fail ("STATMOUNT_MNT_POINT not set in statmount\n" );
767+ goto out ;
768+ }
769+
770+ if (!(sm -> mask & STATMOUNT_MNT_ROOT )) {
771+ ksft_test_result_fail ("STATMOUNT_MNT_ROOT not set in statmount\n" );
772+ goto out ;
773+ }
774+
775+ if (strcmp (subdir , sm -> str + sm -> mnt_point ) != 0 ) {
776+ ksft_test_result_fail ("statmount returned incorrect mnt_point,"
777+ "statmount mnt_point: %s != %s\n" , sm -> str + sm -> mnt_point , subdir );
778+ goto out ;
779+ }
780+
781+ if (strcmp (root , sm -> str + sm -> mnt_root ) != 0 ) {
782+ ksft_test_result_fail ("statmount returned incorrect mnt_root,"
783+ "statmount mnt_root: %s != %s\n" , sm -> str + sm -> mnt_root , root );
784+ goto out ;
785+ }
786+
787+ ksft_test_result_pass ("statmount by fd\n" );
788+ goto out ;
789+ err_chroot :
790+ chroot ("." );
791+ out :
792+ free (sm );
793+ err_fd :
794+ close (fd );
795+ err_tmproot :
796+ rmdir (tmproot );
797+ err_subdir :
798+ umount2 (subdir , MNT_DETACH );
799+ rmdir (subdir );
800+ err_tmpdir :
801+ umount2 (tmpdir , MNT_DETACH );
802+ rmdir (tmpdir );
803+ }
804+
805+ static void test_statmount_by_fd_unmounted (void )
806+ {
807+ const char root [] = "/test.unmounted" ;
808+ char tmpdir [] = "/statmount.fd.XXXXXX" ;
809+ char subdir [PATH_MAX ];
810+ int fd ;
811+ struct statmount * sm = NULL ;
812+
813+ if (!mkdtemp (tmpdir )) {
814+ ksft_perror ("mkdtemp" );
815+ return ;
816+ }
817+
818+ if (mount ("statmount.test" , tmpdir , "tmpfs" , 0 , NULL )) {
819+ ksft_perror ("mount" );
820+ rmdir (tmpdir );
821+ return ;
822+ }
823+
824+ snprintf (subdir , PATH_MAX , "%s%s" , tmpdir , root );
825+
826+ if (mkdir (subdir , 0755 )) {
827+ ksft_perror ("mkdir" );
828+ goto err_tmpdir ;
829+ }
830+
831+ if (mount (subdir , subdir , 0 , MS_BIND , NULL )) {
832+ ksft_perror ("mount" );
833+ goto err_subdir ;
834+ }
835+
836+ fd = open (subdir , O_PATH );
837+ if (fd < 0 ) {
838+ ksft_perror ("open" );
839+ goto err_subdir ;
840+ }
841+
842+ if (umount2 (tmpdir , MNT_DETACH )) {
843+ ksft_perror ("umount2" );
844+ goto err_fd ;
845+ }
846+
847+ sm = statmount_alloc (0 , fd , STATMOUNT_MNT_POINT | STATMOUNT_MNT_ROOT , STATMOUNT_BY_FD );
848+ if (!sm ) {
849+ ksft_test_result_fail ("statmount by fd unmounted: %s\n" ,
850+ strerror (errno ));
851+ goto err_sm ;
852+ }
853+
854+ if (sm -> size < sizeof (* sm )) {
855+ ksft_test_result_fail ("unexpected size: %u < %u\n" ,
856+ sm -> size , (uint32_t ) sizeof (* sm ));
857+ goto err_sm ;
858+ }
859+
860+ if (sm -> mask & STATMOUNT_MNT_POINT ) {
861+ ksft_test_result_fail ("STATMOUNT_MNT_POINT unexpectedly set in mask\n" );
862+ goto err_sm ;
863+ }
864+
865+ if (!(sm -> mask & STATMOUNT_MNT_ROOT )) {
866+ ksft_test_result_fail ("STATMOUNT_MNT_ROOT not set in mask\n" );
867+ goto err_sm ;
868+ }
869+
870+ if (strcmp (sm -> str + sm -> mnt_root , root ) != 0 ) {
871+ ksft_test_result_fail ("statmount returned incorrect mnt_root,"
872+ "statmount mnt_root: %s != %s\n" ,
873+ sm -> str + sm -> mnt_root , root );
874+ goto err_sm ;
875+ }
876+
877+ ksft_test_result_pass ("statmount by fd on unmounted mount\n" );
878+ err_sm :
879+ free (sm );
880+ err_fd :
881+ close (fd );
882+ err_subdir :
883+ umount2 (subdir , MNT_DETACH );
884+ rmdir (subdir );
885+ err_tmpdir :
886+ umount2 (tmpdir , MNT_DETACH );
887+ rmdir (tmpdir );
888+ }
889+
661890#define str_off (memb ) (offsetof(struct statmount, memb) / sizeof(uint32_t))
662891
663892int main (void )
@@ -669,14 +898,14 @@ int main(void)
669898
670899 ksft_print_header ();
671900
672- ret = statmount (0 , 0 , 0 , NULL , 0 , 0 );
901+ ret = statmount (0 , 0 , 0 , 0 , NULL , 0 , 0 );
673902 assert (ret == -1 );
674903 if (errno == ENOSYS )
675904 ksft_exit_skip ("statmount() syscall not supported\n" );
676905
677906 setup_namespace ();
678907
679- ksft_set_plan (15 );
908+ ksft_set_plan (17 );
680909 test_listmount_empty_root ();
681910 test_statmount_zero_mask ();
682911 test_statmount_mnt_basic ();
@@ -693,6 +922,8 @@ int main(void)
693922 test_statmount_string (all_mask , str_off (fs_type ), "fs type & all" );
694923
695924 test_listmount_tree ();
925+ test_statmount_by_fd_unmounted ();
926+ test_statmount_by_fd ();
696927
697928
698929 if (ksft_get_fail_cnt () + ksft_get_error_cnt () > 0 )
0 commit comments