1
1
#include "kerncompat.h"
2
+ #include <sys/stat.h>
2
3
#include <stddef.h>
4
+ #include <fcntl.h>
5
+ #include <unistd.h>
3
6
#include "kernel-shared/ctree.h"
7
+ #include "kernel-shared/disk-io.h"
4
8
#include "crypto/crc32c.h"
9
+ #include "common/device-utils.h"
10
+ #include "common/messages.h"
11
+ #include "image/metadump.h"
5
12
#include "image/common.h"
6
13
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
+
7
73
void csum_block (u8 * buf , size_t len )
8
74
{
9
75
u16 csum_size = btrfs_csum_type_size (BTRFS_CSUM_TYPE_CRC32 );
@@ -13,3 +79,132 @@ void csum_block(u8 *buf, size_t len)
13
79
put_unaligned_le32 (~crc , result );
14
80
memcpy (buf , result , csum_size );
15
81
}
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