⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dm-exception-store.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * dm-exception-store.c * * Copyright (C) 2001-2002 Sistina Software (UK) Limited. * Copyright (C) 2006 Red Hat GmbH * * This file is released under the GPL. */#include "dm.h"#include "dm-snap.h"#include "dm-io.h"#include "kcopyd.h"#include <linux/mm.h>#include <linux/pagemap.h>#include <linux/vmalloc.h>#include <linux/slab.h>#define DM_MSG_PREFIX "snapshots"#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32	/* 16KB *//*----------------------------------------------------------------- * Persistent snapshots, by persistent we mean that the snapshot * will survive a reboot. *---------------------------------------------------------------*//* * We need to store a record of which parts of the origin have * been copied to the snapshot device.  The snapshot code * requires that we copy exception chunks to chunk aligned areas * of the COW store.  It makes sense therefore, to store the * metadata in chunk size blocks. * * There is no backward or forward compatibility implemented, * snapshots with different disk versions than the kernel will * not be usable.  It is expected that "lvcreate" will blank out * the start of a fresh COW device before calling the snapshot * constructor. * * The first chunk of the COW device just contains the header. * After this there is a chunk filled with exception metadata, * followed by as many exception chunks as can fit in the * metadata areas. * * All on disk structures are in little-endian format.  The end * of the exceptions info is indicated by an exception with a * new_chunk of 0, which is invalid since it would point to the * header chunk. *//* * Magic for persistent snapshots: "SnAp" - Feeble isn't it. */#define SNAP_MAGIC 0x70416e53/* * The on-disk version of the metadata. */#define SNAPSHOT_DISK_VERSION 1struct disk_header {	uint32_t magic;	/*	 * Is this snapshot valid.  There is no way of recovering	 * an invalid snapshot.	 */	uint32_t valid;	/*	 * Simple, incrementing version. no backward	 * compatibility.	 */	uint32_t version;	/* In sectors */	uint32_t chunk_size;};struct disk_exception {	uint64_t old_chunk;	uint64_t new_chunk;};struct commit_callback {	void (*callback)(void *, int success);	void *context;};/* * The top level structure for a persistent exception store. */struct pstore {	struct dm_snapshot *snap;	/* up pointer to my snapshot */	int version;	int valid;	uint32_t exceptions_per_area;	/*	 * Now that we have an asynchronous kcopyd there is no	 * need for large chunk sizes, so it wont hurt to have a	 * whole chunks worth of metadata in memory at once.	 */	void *area;	/*	 * Used to keep track of which metadata area the data in	 * 'chunk' refers to.	 */	uint32_t current_area;	/*	 * The next free chunk for an exception.	 */	uint32_t next_free;	/*	 * The index of next free exception in the current	 * metadata area.	 */	uint32_t current_committed;	atomic_t pending_count;	uint32_t callback_count;	struct commit_callback *callbacks;	struct dm_io_client *io_client;	struct workqueue_struct *metadata_wq;};static unsigned sectors_to_pages(unsigned sectors){	return sectors / (PAGE_SIZE >> 9);}static int alloc_area(struct pstore *ps){	int r = -ENOMEM;	size_t len;	len = ps->snap->chunk_size << SECTOR_SHIFT;	/*	 * Allocate the chunk_size block of memory that will hold	 * a single metadata area.	 */	ps->area = vmalloc(len);	if (!ps->area)		return r;	return 0;}static void free_area(struct pstore *ps){	vfree(ps->area);	ps->area = NULL;}struct mdata_req {	struct io_region *where;	struct dm_io_request *io_req;	struct work_struct work;	int result;};static void do_metadata(struct work_struct *work){	struct mdata_req *req = container_of(work, struct mdata_req, work);	req->result = dm_io(req->io_req, 1, req->where, NULL);}/* * Read or write a chunk aligned and sized block of data from a device. */static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata){	struct io_region where = {		.bdev = ps->snap->cow->bdev,		.sector = ps->snap->chunk_size * chunk,		.count = ps->snap->chunk_size,	};	struct dm_io_request io_req = {		.bi_rw = rw,		.mem.type = DM_IO_VMA,		.mem.ptr.vma = ps->area,		.client = ps->io_client,		.notify.fn = NULL,	};	struct mdata_req req;	if (!metadata)		return dm_io(&io_req, 1, &where, NULL);	req.where = &where;	req.io_req = &io_req;	/*	 * Issue the synchronous I/O from a different thread	 * to avoid generic_make_request recursion.	 */	INIT_WORK(&req.work, do_metadata);	queue_work(ps->metadata_wq, &req.work);	flush_workqueue(ps->metadata_wq);	return req.result;}/* * Read or write a metadata area.  Remembering to skip the first * chunk which holds the header. */static int area_io(struct pstore *ps, uint32_t area, int rw){	int r;	uint32_t chunk;	/* convert a metadata area index to a chunk index */	chunk = 1 + ((ps->exceptions_per_area + 1) * area);	r = chunk_io(ps, chunk, rw, 0);	if (r)		return r;	ps->current_area = area;	return 0;}static int zero_area(struct pstore *ps, uint32_t area){	memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);	return area_io(ps, area, WRITE);}static int read_header(struct pstore *ps, int *new_snapshot){	int r;	struct disk_header *dh;	chunk_t chunk_size;	int chunk_size_supplied = 1;	/*	 * Use default chunk size (or hardsect_size, if larger) if none supplied	 */	if (!ps->snap->chunk_size) {        	ps->snap->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,		    bdev_hardsect_size(ps->snap->cow->bdev) >> 9);		ps->snap->chunk_mask = ps->snap->chunk_size - 1;		ps->snap->chunk_shift = ffs(ps->snap->chunk_size) - 1;		chunk_size_supplied = 0;	}	ps->io_client = dm_io_client_create(sectors_to_pages(ps->snap->							     chunk_size));	if (IS_ERR(ps->io_client))		return PTR_ERR(ps->io_client);	r = alloc_area(ps);	if (r)		return r;	r = chunk_io(ps, 0, READ, 1);	if (r)		goto bad;	dh = (struct disk_header *) ps->area;	if (le32_to_cpu(dh->magic) == 0) {		*new_snapshot = 1;		return 0;	}	if (le32_to_cpu(dh->magic) != SNAP_MAGIC) {		DMWARN("Invalid or corrupt snapshot");		r = -ENXIO;		goto bad;	}	*new_snapshot = 0;	ps->valid = le32_to_cpu(dh->valid);	ps->version = le32_to_cpu(dh->version);	chunk_size = le32_to_cpu(dh->chunk_size);	if (!chunk_size_supplied || ps->snap->chunk_size == chunk_size)		return 0;	DMWARN("chunk size %llu in device metadata overrides "	       "table chunk size of %llu.",	       (unsigned long long)chunk_size,	       (unsigned long long)ps->snap->chunk_size);	/* We had a bogus chunk_size. Fix stuff up. */	free_area(ps);	ps->snap->chunk_size = chunk_size;	ps->snap->chunk_mask = chunk_size - 1;	ps->snap->chunk_shift = ffs(chunk_size) - 1;	r = dm_io_client_resize(sectors_to_pages(ps->snap->chunk_size),				ps->io_client);	if (r)		return r;	r = alloc_area(ps);	return r;bad:	free_area(ps);	return r;}static int write_header(struct pstore *ps){	struct disk_header *dh;	memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);	dh = (struct disk_header *) ps->area;	dh->magic = cpu_to_le32(SNAP_MAGIC);	dh->valid = cpu_to_le32(ps->valid);	dh->version = cpu_to_le32(ps->version);	dh->chunk_size = cpu_to_le32(ps->snap->chunk_size);	return chunk_io(ps, 0, WRITE, 1);}/* * Access functions for the disk exceptions, these do the endian conversions. */static struct disk_exception *get_exception(struct pstore *ps, uint32_t index){	BUG_ON(index >= ps->exceptions_per_area);	return ((struct disk_exception *) ps->area) + index;}static void read_exception(struct pstore *ps,			   uint32_t index, struct disk_exception *result){	struct disk_exception *e = get_exception(ps, index);	/* copy it */	result->old_chunk = le64_to_cpu(e->old_chunk);	result->new_chunk = le64_to_cpu(e->new_chunk);}static void write_exception(struct pstore *ps,			    uint32_t index, struct disk_exception *de){	struct disk_exception *e = get_exception(ps, index);	/* copy it */	e->old_chunk = cpu_to_le64(de->old_chunk);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -