@@ -45,8 +45,11 @@ static size_t fill_cpio(struct initramfs_test_cpio *cs, size_t csz, char *out)
4545 c -> mtime , c -> filesize , c -> devmajor , c -> devminor ,
4646 c -> rdevmajor , c -> rdevminor , c -> namesize , c -> csum ,
4747 c -> fname ) + 1 ;
48+
4849 pr_debug ("packing (%zu): %.*s\n" , thislen , (int )thislen , pos );
49- off += thislen ;
50+ if (thislen != CPIO_HDRLEN + c -> namesize )
51+ pr_debug ("padded to: %u\n" , CPIO_HDRLEN + c -> namesize );
52+ off += CPIO_HDRLEN + c -> namesize ;
5053 while (off & 3 )
5154 out [off ++ ] = '\0' ;
5255
@@ -383,6 +386,67 @@ static void __init initramfs_test_many(struct kunit *test)
383386 kfree (cpio_srcbuf );
384387}
385388
389+ /*
390+ * An initramfs filename is namesize in length, including the zero-terminator.
391+ * A filename can be zero-terminated prior to namesize, with the remainder used
392+ * as padding. This can be useful for e.g. alignment of file data segments with
393+ * a 4KB filesystem block, allowing for extent sharing (reflinks) between cpio
394+ * source and destination. This hack works with both GNU cpio and initramfs, as
395+ * long as PATH_MAX isn't exceeded.
396+ */
397+ static void __init initramfs_test_fname_pad (struct kunit * test )
398+ {
399+ char * err ;
400+ size_t len ;
401+ struct file * file ;
402+ char fdata [] = "this file data is aligned at 4K in the archive" ;
403+ struct test_fname_pad {
404+ char padded_fname [4096 - CPIO_HDRLEN ];
405+ char cpio_srcbuf [CPIO_HDRLEN + PATH_MAX + 3 + sizeof (fdata )];
406+ } * tbufs = kzalloc (sizeof (struct test_fname_pad ), GFP_KERNEL );
407+ struct initramfs_test_cpio c [] = { {
408+ .magic = "070701" ,
409+ .ino = 1 ,
410+ .mode = S_IFREG | 0777 ,
411+ .uid = 0 ,
412+ .gid = 0 ,
413+ .nlink = 1 ,
414+ .mtime = 1 ,
415+ .filesize = sizeof (fdata ),
416+ .devmajor = 0 ,
417+ .devminor = 1 ,
418+ .rdevmajor = 0 ,
419+ .rdevminor = 0 ,
420+ /* align file data at 4K archive offset via padded fname */
421+ .namesize = 4096 - CPIO_HDRLEN ,
422+ .csum = 0 ,
423+ .fname = tbufs -> padded_fname ,
424+ .data = fdata ,
425+ } };
426+
427+ memcpy (tbufs -> padded_fname , "padded_fname" , sizeof ("padded_fname" ));
428+ len = fill_cpio (c , ARRAY_SIZE (c ), tbufs -> cpio_srcbuf );
429+
430+ err = unpack_to_rootfs (tbufs -> cpio_srcbuf , len );
431+ KUNIT_EXPECT_NULL (test , err );
432+
433+ file = filp_open (c [0 ].fname , O_RDONLY , 0 );
434+ if (IS_ERR (file )) {
435+ KUNIT_FAIL (test , "open failed" );
436+ goto out ;
437+ }
438+
439+ /* read back file contents into @cpio_srcbuf and confirm match */
440+ len = kernel_read (file , tbufs -> cpio_srcbuf , c [0 ].filesize , NULL );
441+ KUNIT_EXPECT_EQ (test , len , c [0 ].filesize );
442+ KUNIT_EXPECT_MEMEQ (test , tbufs -> cpio_srcbuf , c [0 ].data , len );
443+
444+ fput (file );
445+ KUNIT_EXPECT_EQ (test , init_unlink (c [0 ].fname ), 0 );
446+ out :
447+ kfree (tbufs );
448+ }
449+
386450/*
387451 * The kunit_case/_suite struct cannot be marked as __initdata as this will be
388452 * used in debugfs to retrieve results after test has run.
@@ -394,6 +458,7 @@ static struct kunit_case __refdata initramfs_test_cases[] = {
394458 KUNIT_CASE (initramfs_test_csum ),
395459 KUNIT_CASE (initramfs_test_hardlink ),
396460 KUNIT_CASE (initramfs_test_many ),
461+ KUNIT_CASE (initramfs_test_fname_pad ),
397462 {},
398463};
399464
0 commit comments