11#include "kerncompat.h"
2+ #include <sys/stat.h>
23#include <stddef.h>
4+ #include <fcntl.h>
5+ #include <unistd.h>
36#include "kernel-shared/ctree.h"
7+ #include "kernel-shared/disk-io.h"
48#include "crypto/crc32c.h"
9+ #include "common/device-utils.h"
10+ #include "common/messages.h"
11+ #include "image/metadump.h"
512#include "image/common.h"
613
14+ const struct dump_version dump_versions [] = {
15+ /*
16+ * The original format, which only supports tree blocks and free space
17+ * cache dump.
18+ */
19+ { .version = 0 ,
20+ .max_pending_size = SZ_256K ,
21+ .magic_cpu = 0xbd5c25e27295668bULL ,
22+ .extra_sb_flags = 1 },
23+ #if EXPERIMENTAL
24+ /*
25+ * The new format, with much larger item size to contain any data
26+ * extents.
27+ */
28+ { .version = 1 ,
29+ .max_pending_size = SZ_256M ,
30+ .magic_cpu = 0x31765f506d55445fULL , /* ascii _DUmP_v1, no null */
31+ .extra_sb_flags = 0 },
32+ #endif
33+ };
34+
35+ const struct dump_version * current_version = & dump_versions [0 ];
36+
37+ int detect_version (FILE * in )
38+ {
39+ struct meta_cluster * cluster ;
40+ u8 buf [IMAGE_BLOCK_SIZE ];
41+ bool found = false;
42+ int i ;
43+ int ret ;
44+
45+ if (fseek (in , 0 , SEEK_SET ) < 0 ) {
46+ error ("seek failed: %m" );
47+ return - errno ;
48+ }
49+ ret = fread (buf , IMAGE_BLOCK_SIZE , 1 , in );
50+ if (!ret ) {
51+ error ("failed to read header" );
52+ return - EIO ;
53+ }
54+
55+ fseek (in , 0 , SEEK_SET );
56+ cluster = (struct meta_cluster * )buf ;
57+ for (i = 0 ; i < ARRAY_SIZE (dump_versions ); i ++ ) {
58+ if (le64_to_cpu (cluster -> header .magic ) ==
59+ dump_versions [i ].magic_cpu ) {
60+ found = true;
61+ current_version = & dump_versions [i ];
62+ break ;
63+ }
64+ }
65+
66+ if (!found ) {
67+ error ("unrecognized header format" );
68+ return - EINVAL ;
69+ }
70+ return 0 ;
71+ }
72+
773void csum_block (u8 * buf , size_t len )
874{
975 u16 csum_size = btrfs_csum_type_size (BTRFS_CSUM_TYPE_CRC32 );
@@ -13,3 +79,132 @@ void csum_block(u8 *buf, size_t len)
1379 put_unaligned_le32 (~crc , result );
1480 memcpy (buf , result , csum_size );
1581}
82+
83+ void write_backup_supers (int fd , u8 * buf )
84+ {
85+ struct btrfs_super_block * super = (struct btrfs_super_block * )buf ;
86+ struct stat st ;
87+ u64 size ;
88+ u64 bytenr ;
89+ int i ;
90+ int ret ;
91+
92+ if (fstat (fd , & st )) {
93+ error (
94+ "cannot stat restore point, won't be able to write backup supers: %m" );
95+ return ;
96+ }
97+
98+ size = device_get_partition_size_fd_stat (fd , & st );
99+
100+ for (i = 1 ; i < BTRFS_SUPER_MIRROR_MAX ; i ++ ) {
101+ bytenr = btrfs_sb_offset (i );
102+ if (bytenr + BTRFS_SUPER_INFO_SIZE > size )
103+ break ;
104+ btrfs_set_super_bytenr (super , bytenr );
105+ csum_block (buf , BTRFS_SUPER_INFO_SIZE );
106+ ret = pwrite (fd , buf , BTRFS_SUPER_INFO_SIZE , bytenr );
107+ if (ret < BTRFS_SUPER_INFO_SIZE ) {
108+ if (ret < 0 )
109+ error (
110+ "problem writing out backup super block %d: %m" , i );
111+ else
112+ error ("short write writing out backup super block" );
113+ break ;
114+ }
115+ }
116+ }
117+
118+ int update_disk_super_on_device (struct btrfs_fs_info * info ,
119+ const char * other_dev , u64 cur_devid )
120+ {
121+ struct btrfs_key key ;
122+ struct extent_buffer * leaf ;
123+ struct btrfs_path path ;
124+ struct btrfs_dev_item * dev_item ;
125+ struct btrfs_super_block disk_super ;
126+ char dev_uuid [BTRFS_UUID_SIZE ];
127+ char fs_uuid [BTRFS_UUID_SIZE ];
128+ u64 devid , type , io_align , io_width ;
129+ u64 sector_size , total_bytes , bytes_used ;
130+ int fp = -1 ;
131+ int ret ;
132+
133+ key .objectid = BTRFS_DEV_ITEMS_OBJECTID ;
134+ key .type = BTRFS_DEV_ITEM_KEY ;
135+ key .offset = cur_devid ;
136+
137+ btrfs_init_path (& path );
138+ ret = btrfs_search_slot (NULL , info -> chunk_root , & key , & path , 0 , 0 );
139+ if (ret ) {
140+ error ("search key failed: %d" , ret );
141+ ret = - EIO ;
142+ goto out ;
143+ }
144+
145+ leaf = path .nodes [0 ];
146+ dev_item = btrfs_item_ptr (leaf , path .slots [0 ],
147+ struct btrfs_dev_item );
148+
149+ devid = btrfs_device_id (leaf , dev_item );
150+ if (devid != cur_devid ) {
151+ error ("devid mismatch: %llu != %llu" , devid , cur_devid );
152+ ret = - EIO ;
153+ goto out ;
154+ }
155+
156+ type = btrfs_device_type (leaf , dev_item );
157+ io_align = btrfs_device_io_align (leaf , dev_item );
158+ io_width = btrfs_device_io_width (leaf , dev_item );
159+ sector_size = btrfs_device_sector_size (leaf , dev_item );
160+ total_bytes = btrfs_device_total_bytes (leaf , dev_item );
161+ bytes_used = btrfs_device_bytes_used (leaf , dev_item );
162+ read_extent_buffer (leaf , dev_uuid , (unsigned long )btrfs_device_uuid (dev_item ), BTRFS_UUID_SIZE );
163+ read_extent_buffer (leaf , fs_uuid , (unsigned long )btrfs_device_fsid (dev_item ), BTRFS_UUID_SIZE );
164+
165+ btrfs_release_path (& path );
166+
167+ printf ("update disk super on %s devid=%llu\n" , other_dev , devid );
168+
169+ /* update other devices' super block */
170+ fp = open (other_dev , O_CREAT | O_RDWR , 0600 );
171+ if (fp < 0 ) {
172+ error ("could not open %s: %m" , other_dev );
173+ ret = - EIO ;
174+ goto out ;
175+ }
176+
177+ memcpy (& disk_super , info -> super_copy , BTRFS_SUPER_INFO_SIZE );
178+
179+ dev_item = & disk_super .dev_item ;
180+
181+ btrfs_set_stack_device_type (dev_item , type );
182+ btrfs_set_stack_device_id (dev_item , devid );
183+ btrfs_set_stack_device_total_bytes (dev_item , total_bytes );
184+ btrfs_set_stack_device_bytes_used (dev_item , bytes_used );
185+ btrfs_set_stack_device_io_align (dev_item , io_align );
186+ btrfs_set_stack_device_io_width (dev_item , io_width );
187+ btrfs_set_stack_device_sector_size (dev_item , sector_size );
188+ memcpy (dev_item -> uuid , dev_uuid , BTRFS_UUID_SIZE );
189+ memcpy (dev_item -> fsid , fs_uuid , BTRFS_UUID_SIZE );
190+ csum_block ((u8 * )& disk_super , BTRFS_SUPER_INFO_SIZE );
191+
192+ ret = pwrite (fp , & disk_super , BTRFS_SUPER_INFO_SIZE , BTRFS_SUPER_INFO_OFFSET );
193+ if (ret != BTRFS_SUPER_INFO_SIZE ) {
194+ if (ret < 0 ) {
195+ errno = ret ;
196+ error ("cannot write superblock: %m" );
197+ } else {
198+ error ("cannot write superblock" );
199+ }
200+ ret = - EIO ;
201+ goto out ;
202+ }
203+
204+ write_backup_supers (fp , (u8 * )& disk_super );
205+
206+ out :
207+ if (fp != -1 )
208+ close (fp );
209+ return ret ;
210+ }
0 commit comments