1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-30 20:23:49 +03:00
Files
lvm2/lib/label/label.h
David Teigland 899fabb26b label_scan/vg_read: use label_read_data to avoid disk reads
The new label_scan() function reads a large buffer of data
from the start of the disk, and saves it so that multiple
structs can be read from it.  Previously, only the label_header
was read from this buffer, and the code which needed data
structures that immediately followed the label_header would
read those from disk separately.  This created a large
number of small, unnecessary disk reads.

In each place that the two read paths (label_scan and vg_read)
need to read data from disk, first check if that data is
already available from the label_read_data buffer, and if
so just copy it from the buffer instead of reading from disk.

Code changes
------------

- passing the label_read_data struct down through
  both read paths to make it available.

- before every disk read, first check if the location
  and size of the desired piece of data exists fully
  in the label_read_data buffer, and if so copy it
  from there.  Otherwise, use the existing code to
  read the data from disk.

- adding some log_error messages on existing error paths
  that were already being updated for the reasons above.

- using similar naming for parallel functions on the two
  parallel read paths that are being updated above.

  label_scan path calls:
  read_metadata_location_summary, text_read_metadata_summary

  vg_read path calls:
  read_metadata_location_vg, text_read_metadata_file

  Previously, those functions were named:

  label_scan path calls:
  vgname_from_mda, text_vgsummary_import

  vg_read path calls:
  _find_vg_rlocn, text_vg_import_fd

I/O changes
-----------

In the label_scan path, the following data is either copied
from label_read_data or read from disk for each PV:

- label_header and pv_header
- mda_header (in _raw_read_mda_header)
- vg metadata name (in read_metadata_location_summary)
- vg metadata (in config_file_read_fd)

Total of 4 reads per PV in the label_scan path.

In the vg_read path, the following data is either copied from
label_read_data or read from disk for each PV:

- mda_header (in _raw_read_mda_header)
- vg metadata name (in read_metadata_location_vg)
- vg metadata (in config_file_read_fd)

Total of 3 reads per PV in the vg_read path.

For a common read/reporting command, each PV will be:

- read by the command's initial lvmcache_label_scan()
- read by lvmcache_label_rescan_vg() at the start of vg_read()
- read by vg_read()

Previously, this would cause 11 synchronous disk reads per PV:
4 from lvmcache_label_scan(), 4 from lvmcache_label_rescan_vg()
and 3 from vg_read().

With this commit's optimization, there are now 2 async disk reads
per PV: 1 from lvmcache_label_scan() and 1 from
lvmcache_label_rescan_vg().

When a second mda is used on a PV, it is located at the
end of the PV.  This second mda and copy of metadata will
not be found in the label_read_data buffer, and will always
require separate disk reads.
2017-10-27 14:59:29 -05:00

128 lines
3.3 KiB
C

/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_LABEL_H
#define _LVM_LABEL_H
#include "uuid.h"
#include "device.h"
#include "toolcontext.h"
#define LABEL_ID "LABELONE"
#define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */
#define LABEL_SCAN_SECTORS 4L
#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
struct labeller;
void allow_reads_with_lvmetad(void);
struct label_read_data {
struct dev_async_io *aio;
char *buf; /* points to aio->buf */
struct device *dev;
struct dm_list list;
int buf_len; /* same as aio->buf_len */
int result; /* same as aio->result */
int try_sync;
int process_done;
};
/* On disk - 32 bytes */
struct label_header {
int8_t id[8]; /* LABELONE */
uint64_t sector_xl; /* Sector number of this label */
uint32_t crc_xl; /* From next field to end of sector */
uint32_t offset_xl; /* Offset from start of struct to contents */
int8_t type[8]; /* LVM2 001 */
} __attribute__ ((packed));
/* In core */
struct label {
char type[8];
uint64_t sector;
struct labeller *labeller;
struct device *dev;
void *info;
};
struct labeller;
struct label_ops {
/*
* Is the device labelled with this format ?
*/
int (*can_handle) (struct labeller * l, void *buf, uint64_t sector);
/*
* Write a label to a volume.
*/
int (*write) (struct label * label, void *buf);
/*
* Read a label from a volume.
*/
int (*read) (struct labeller * l, struct device * dev,
void *label_buf,
struct label_read_data *ld, struct label ** label);
/*
* Additional consistency checks for the paranoid.
*/
int (*verify) (struct labeller * l, void *buf, uint64_t sector);
/*
* Populate label_type etc.
*/
int (*initialise_label) (struct labeller * l, struct label * label);
/*
* Destroy a previously read label.
*/
void (*destroy_label) (struct labeller * l, struct label * label);
/*
* Destructor.
*/
void (*destroy) (struct labeller * l);
};
struct labeller {
struct label_ops *ops;
const struct format_type *fmt;
};
int label_init(void);
void label_exit(void);
int label_register_handler(struct labeller *handler);
struct labeller *label_get_handler(const char *name);
int label_remove(struct device *dev);
int label_read(struct device *dev, struct label **label, uint64_t scan_sector);
int label_write(struct device *dev, struct label *label);
int label_verify(struct device *dev);
struct label *label_create(struct labeller *labeller);
void label_destroy(struct label *label);
int label_scan_force(struct cmd_context *cmd);
int label_scan(struct cmd_context *cmd);
int label_scan_devs(struct cmd_context *cmd, struct dm_list *devs);
struct label_read_data *get_label_read_data(struct cmd_context *cmd, struct device *dev);
void label_scan_destroy(struct cmd_context *cmd);
#endif