4 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 /* FIXME Allow for larger labels? Restricted to single sector currently */
32 * Internal labeller struct.
41 static struct dm_list _labellers
;
43 static struct labeller_i
*_alloc_li(const char *name
, struct labeller
*l
)
45 struct labeller_i
*li
;
48 len
= sizeof(*li
) + strlen(name
) + 1;
50 if (!(li
= dm_malloc(len
))) {
51 log_error("Couldn't allocate memory for labeller list object.");
56 strcpy(li
->name
, name
);
61 static void _free_li(struct labeller_i
*li
)
68 dm_list_init(&_labellers
);
74 struct dm_list
*c
, *n
;
75 struct labeller_i
*li
;
77 for (c
= _labellers
.n
; c
&& c
!= &_labellers
; c
= n
) {
79 li
= dm_list_item(c
, struct labeller_i
);
80 li
->l
->ops
->destroy(li
->l
);
84 dm_list_init(&_labellers
);
87 int label_register_handler(const char *name
, struct labeller
*handler
)
89 struct labeller_i
*li
;
91 if (!(li
= _alloc_li(name
, handler
)))
94 dm_list_add(&_labellers
, &li
->list
);
98 struct labeller
*label_get_handler(const char *name
)
100 struct labeller_i
*li
;
102 dm_list_iterate_items(li
, &_labellers
)
103 if (!strcmp(li
->name
, name
))
109 static struct labeller
*_find_labeller(struct device
*dev
, char *buf
,
110 uint64_t *label_sector
,
111 uint64_t scan_sector
)
113 struct labeller_i
*li
;
114 struct labeller
*r
= NULL
;
115 struct label_header
*lh
;
116 struct lvmcache_info
*info
;
119 char readbuf
[LABEL_SCAN_SIZE
] __attribute((aligned(8)));
121 if (!dev_read(dev
, scan_sector
<< SECTOR_SHIFT
,
122 LABEL_SCAN_SIZE
, readbuf
)) {
123 log_debug("%s: Failed to read label area", dev_name(dev
));
127 /* Scan a few sectors for a valid label */
128 for (sector
= 0; sector
< LABEL_SCAN_SECTORS
;
129 sector
+= LABEL_SIZE
>> SECTOR_SHIFT
) {
130 lh
= (struct label_header
*) (readbuf
+
131 (sector
<< SECTOR_SHIFT
));
133 if (!strncmp((char *)lh
->id
, LABEL_ID
, sizeof(lh
->id
))) {
135 log_error("Ignoring additional label on %s at "
136 "sector %" PRIu64
, dev_name(dev
),
137 sector
+ scan_sector
);
139 if (xlate64(lh
->sector_xl
) != sector
+ scan_sector
) {
140 log_info("%s: Label for sector %" PRIu64
141 " found at sector %" PRIu64
142 " - ignoring", dev_name(dev
),
143 (uint64_t)xlate64(lh
->sector_xl
),
144 sector
+ scan_sector
);
147 if (calc_crc(INITIAL_CRC
, &lh
->offset_xl
, LABEL_SIZE
-
148 ((uintptr_t) &lh
->offset_xl
- (uintptr_t) lh
)) !=
149 xlate32(lh
->crc_xl
)) {
150 log_info("Label checksum incorrect on %s - "
151 "ignoring", dev_name(dev
));
158 dm_list_iterate_items(li
, &_labellers
) {
159 if (li
->l
->ops
->can_handle(li
->l
, (char *) lh
,
160 sector
+ scan_sector
)) {
161 log_very_verbose("%s: %s label detected",
162 dev_name(dev
), li
->name
);
164 log_error("Ignoring additional label "
165 "on %s at sector %" PRIu64
,
167 sector
+ scan_sector
);
171 memcpy(buf
, lh
, LABEL_SIZE
);
173 *label_sector
= sector
+ scan_sector
;
182 if ((info
= info_from_pvid(dev
->pvid
, 0)))
183 lvmcache_update_vgname_and_id(info
, info
->fmt
->orphan_vg_name
,
184 info
->fmt
->orphan_vg_name
,
186 log_very_verbose("%s: No label detected", dev_name(dev
));
192 /* FIXME Also wipe associated metadata area headers? */
193 int label_remove(struct device
*dev
)
195 char buf
[LABEL_SIZE
] __attribute((aligned(8)));
196 char readbuf
[LABEL_SCAN_SIZE
] __attribute((aligned(8)));
200 struct labeller_i
*li
;
201 struct label_header
*lh
;
203 memset(buf
, 0, LABEL_SIZE
);
205 log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev
));
211 * We flush the device just in case someone is stupid
212 * enough to be trying to import an open pv into lvm.
216 if (!dev_read(dev
, UINT64_C(0), LABEL_SCAN_SIZE
, readbuf
)) {
217 log_debug("%s: Failed to read label area", dev_name(dev
));
221 /* Scan first few sectors for anything looking like a label */
222 for (sector
= 0; sector
< LABEL_SCAN_SECTORS
;
223 sector
+= LABEL_SIZE
>> SECTOR_SHIFT
) {
224 lh
= (struct label_header
*) (readbuf
+
225 (sector
<< SECTOR_SHIFT
));
229 if (!strncmp((char *)lh
->id
, LABEL_ID
, sizeof(lh
->id
))) {
230 if (xlate64(lh
->sector_xl
) == sector
)
233 dm_list_iterate_items(li
, &_labellers
) {
234 if (li
->l
->ops
->can_handle(li
->l
, (char *) lh
,
243 log_info("%s: Wiping label at sector %" PRIu64
,
244 dev_name(dev
), sector
);
245 if (!dev_write(dev
, sector
<< SECTOR_SHIFT
, LABEL_SIZE
,
247 log_error("Failed to remove label from %s at "
248 "sector %" PRIu64
, dev_name(dev
),
262 int label_read(struct device
*dev
, struct label
**result
,
263 uint64_t scan_sector
)
265 char buf
[LABEL_SIZE
] __attribute((aligned(8)));
268 struct lvmcache_info
*info
;
271 if ((info
= info_from_pvid(dev
->pvid
, 1))) {
272 log_debug("Using cached label for %s", dev_name(dev
));
273 *result
= info
->label
;
277 if (!dev_open(dev
)) {
280 if ((info
= info_from_pvid(dev
->pvid
, 0)))
281 lvmcache_update_vgname_and_id(info
, info
->fmt
->orphan_vg_name
,
282 info
->fmt
->orphan_vg_name
,
288 if (!(l
= _find_labeller(dev
, buf
, §or
, scan_sector
)))
291 if ((r
= (l
->ops
->read
)(l
, dev
, buf
, result
)) && result
&& *result
)
292 (*result
)->sector
= sector
;
301 /* Caller may need to use label_get_handler to create label struct! */
302 int label_write(struct device
*dev
, struct label
*label
)
304 char buf
[LABEL_SIZE
] __attribute((aligned(8)));
305 struct label_header
*lh
= (struct label_header
*) buf
;
308 if (!label
->labeller
->ops
->write
) {
309 log_error("Label handler does not support label writes");
313 if ((LABEL_SIZE
+ (label
->sector
<< SECTOR_SHIFT
)) > LABEL_SCAN_SIZE
) {
314 log_error("Label sector %" PRIu64
" beyond range (%ld)",
315 label
->sector
, LABEL_SCAN_SECTORS
);
319 memset(buf
, 0, LABEL_SIZE
);
321 strncpy((char *)lh
->id
, LABEL_ID
, sizeof(lh
->id
));
322 lh
->sector_xl
= xlate64(label
->sector
);
323 lh
->offset_xl
= xlate32(sizeof(*lh
));
325 if (!(label
->labeller
->ops
->write
)(label
, buf
))
328 lh
->crc_xl
= xlate32(calc_crc(INITIAL_CRC
, &lh
->offset_xl
, LABEL_SIZE
-
329 ((uintptr_t) &lh
->offset_xl
- (uintptr_t) lh
)));
334 log_info("%s: Writing label to sector %" PRIu64
" with stored offset %"
335 PRIu32
".", dev_name(dev
), label
->sector
,
336 xlate32(lh
->offset_xl
));
337 if (!dev_write(dev
, label
->sector
<< SECTOR_SHIFT
, LABEL_SIZE
, buf
)) {
338 log_debug("Failed to write label to %s", dev_name(dev
));
349 int label_verify(struct device
*dev
)
352 char buf
[LABEL_SIZE
] __attribute((aligned(8)));
354 struct lvmcache_info
*info
;
357 if (!dev_open(dev
)) {
358 if ((info
= info_from_pvid(dev
->pvid
, 0)))
359 lvmcache_update_vgname_and_id(info
, info
->fmt
->orphan_vg_name
,
360 info
->fmt
->orphan_vg_name
,
366 if (!(l
= _find_labeller(dev
, buf
, §or
, UINT64_C(0))))
369 r
= l
->ops
->verify
? l
->ops
->verify(l
, buf
, sector
) : 1;
378 void label_destroy(struct label
*label
)
380 label
->labeller
->ops
->destroy_label(label
->labeller
, label
);
384 struct label
*label_create(struct labeller
*labeller
)
388 if (!(label
= dm_malloc(sizeof(*label
)))) {
389 log_error("label allocaction failed");
392 memset(label
, 0, sizeof(*label
));
394 label
->labeller
= labeller
;
396 labeller
->ops
->initialise_label(labeller
, label
);