1/*	$NetBSD: format_pool.c,v 1.1.1.2 2009/12/02 00:26:50 haad Exp $	*/
2
3/*
4 * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
6 *
7 * This file is part of LVM2.
8 *
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.
12 *
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
16 */
17
18#include "lib.h"
19#include "label.h"
20#include "metadata.h"
21#include "limits.h"
22#include "display.h"
23#include "toolcontext.h"
24#include "lvmcache.h"
25#include "disk_rep.h"
26#include "format_pool.h"
27#include "pool_label.h"
28
29/* Must be called after pvs are imported */
30static struct user_subpool *_build_usp(struct dm_list *pls, struct dm_pool *mem,
31				       int *sps)
32{
33	struct pool_list *pl;
34	struct user_subpool *usp = NULL, *cur_sp = NULL;
35	struct user_device *cur_dev = NULL;
36
37	/*
38	 * FIXME: Need to do some checks here - I'm tempted to add a
39	 * user_pool structure and build the entire thing to check against.
40	 */
41	dm_list_iterate_items(pl, pls) {
42		*sps = pl->pd.pl_subpools;
43		if (!usp && (!(usp = dm_pool_zalloc(mem, sizeof(*usp) * (*sps))))) {
44			log_error("Unable to allocate %d subpool structures",
45				  *sps);
46			return 0;
47		}
48
49		if (cur_sp != &usp[pl->pd.pl_sp_id]) {
50			cur_sp = &usp[pl->pd.pl_sp_id];
51
52			cur_sp->id = pl->pd.pl_sp_id;
53			cur_sp->striping = pl->pd.pl_striping;
54			cur_sp->num_devs = pl->pd.pl_sp_devs;
55			cur_sp->type = pl->pd.pl_sp_type;
56			cur_sp->initialized = 1;
57		}
58
59		if (!cur_sp->devs &&
60		    (!(cur_sp->devs =
61		       dm_pool_zalloc(mem,
62				   sizeof(*usp->devs) * pl->pd.pl_sp_devs)))) {
63
64			log_error("Unable to allocate %d pool_device "
65				  "structures", pl->pd.pl_sp_devs);
66			return 0;
67		}
68
69		cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid];
70		cur_dev->sp_id = cur_sp->id;
71		cur_dev->devid = pl->pd.pl_sp_id;
72		cur_dev->blocks = pl->pd.pl_blocks;
73		cur_dev->pv = pl->pv;
74		cur_dev->initialized = 1;
75	}
76
77	return usp;
78}
79
80static int _check_usp(char *vgname, struct user_subpool *usp, int sp_count)
81{
82	int i;
83	unsigned j;
84
85	for (i = 0; i < sp_count; i++) {
86		if (!usp[i].initialized) {
87			log_error("Missing subpool %d in pool %s", i, vgname);
88			return 0;
89		}
90		for (j = 0; j < usp[i].num_devs; j++) {
91			if (!usp[i].devs[j].initialized) {
92				log_error("Missing device %u for subpool %d"
93					  " in pool %s", j, i, vgname);
94				return 0;
95			}
96
97		}
98	}
99
100	return 1;
101}
102
103static struct volume_group *_build_vg_from_pds(struct format_instance
104					       *fid, struct dm_pool *mem,
105					       struct dm_list *pds)
106{
107	struct dm_pool *smem = fid->fmt->cmd->mem;
108	struct volume_group *vg = NULL;
109	struct user_subpool *usp = NULL;
110	int sp_count;
111
112	if (!(vg = dm_pool_zalloc(smem, sizeof(*vg)))) {
113		log_error("Unable to allocate volume group structure");
114		return NULL;
115	}
116
117	vg->cmd = fid->fmt->cmd;
118	vg->vgmem = mem;
119	vg->fid = fid;
120	vg->name = NULL;
121	vg->status = 0;
122	vg->extent_count = 0;
123	vg->pv_count = 0;
124	vg->seqno = 1;
125	vg->system_id = NULL;
126	dm_list_init(&vg->pvs);
127	dm_list_init(&vg->lvs);
128	dm_list_init(&vg->tags);
129	dm_list_init(&vg->removed_pvs);
130
131	if (!import_pool_vg(vg, smem, pds))
132		return_NULL;
133
134	if (!import_pool_pvs(fid->fmt, vg, &vg->pvs, smem, pds))
135		return_NULL;
136
137	if (!import_pool_lvs(vg, smem, pds))
138		return_NULL;
139
140	/*
141	 * I need an intermediate subpool structure that contains all the
142	 * relevant info for this.  Then i can iterate through the subpool
143	 * structures for checking, and create the segments
144	 */
145	if (!(usp = _build_usp(pds, mem, &sp_count)))
146		return_NULL;
147
148	/*
149	 * check the subpool structures - we can't handle partial VGs in
150	 * the pool format, so this will error out if we're missing PVs
151	 */
152	if (!_check_usp(vg->name, usp, sp_count))
153		return_NULL;
154
155	if (!import_pool_segments(&vg->lvs, smem, usp, sp_count))
156		return_NULL;
157
158	return vg;
159}
160
161static struct volume_group *_pool_vg_read(struct format_instance *fid,
162				     const char *vg_name,
163				     struct metadata_area *mda __attribute((unused)))
164{
165	struct dm_pool *mem = dm_pool_create("pool vg_read", VG_MEMPOOL_CHUNK);
166	struct dm_list pds;
167	struct volume_group *vg = NULL;
168
169	dm_list_init(&pds);
170
171	/* We can safely ignore the mda passed in */
172
173	if (!mem)
174		return_NULL;
175
176	/* Strip dev_dir if present */
177	vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
178
179	/* Read all the pvs in the vg */
180	if (!read_pool_pds(fid->fmt, vg_name, mem, &pds))
181		goto_out;
182
183	/* Do the rest of the vg stuff */
184	if (!(vg = _build_vg_from_pds(fid, mem, &pds)))
185		goto_out;
186
187	return vg;
188out:
189	dm_pool_destroy(mem);
190	return NULL;
191}
192
193static int _pool_pv_setup(const struct format_type *fmt __attribute((unused)),
194			  uint64_t pe_start __attribute((unused)),
195			  uint32_t extent_count __attribute((unused)),
196			  uint32_t extent_size __attribute((unused)),
197			  unsigned long data_alignment __attribute((unused)),
198			  unsigned long data_alignment_offset __attribute((unused)),
199			  int pvmetadatacopies __attribute((unused)),
200			  uint64_t pvmetadatasize __attribute((unused)),
201			  struct dm_list *mdas __attribute((unused)),
202			  struct physical_volume *pv __attribute((unused)),
203			  struct volume_group *vg __attribute((unused)))
204{
205	return 1;
206}
207
208static int _pool_pv_read(const struct format_type *fmt, const char *pv_name,
209			 struct physical_volume *pv,
210			 struct dm_list *mdas __attribute((unused)),
211			 int scan_label_only __attribute((unused)))
212{
213	struct dm_pool *mem = dm_pool_create("pool pv_read", 1024);
214	struct pool_list *pl;
215	struct device *dev;
216	int r = 0;
217
218	log_very_verbose("Reading physical volume data %s from disk", pv_name);
219
220	if (!mem)
221		return_0;
222
223	if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter)))
224		goto_out;
225
226	/*
227	 * I need to read the disk and populate a pv structure here
228	 * I'll probably need to abstract some of this later for the
229	 * vg_read code
230	 */
231	if (!(pl = read_pool_disk(fmt, dev, mem, NULL)))
232		goto_out;
233
234	if (!import_pool_pv(fmt, fmt->cmd->mem, NULL, pv, pl))
235		goto_out;
236
237	pv->fmt = fmt;
238
239	r = 1;
240
241      out:
242	dm_pool_destroy(mem);
243	return r;
244}
245
246/* *INDENT-OFF* */
247static struct metadata_area_ops _metadata_format_pool_ops = {
248	.vg_read = _pool_vg_read,
249};
250/* *INDENT-ON* */
251
252static struct format_instance *_pool_create_instance(const struct format_type *fmt,
253						const char *vgname __attribute((unused)),
254						const char *vgid __attribute((unused)),
255						void *private __attribute((unused)))
256{
257	struct format_instance *fid;
258	struct metadata_area *mda;
259
260	if (!(fid = dm_pool_zalloc(fmt->cmd->mem, sizeof(*fid)))) {
261		log_error("Unable to allocate format instance structure for "
262			  "pool format");
263		return NULL;
264	}
265
266	fid->fmt = fmt;
267	dm_list_init(&fid->metadata_areas);
268
269	/* Define a NULL metadata area */
270	if (!(mda = dm_pool_zalloc(fmt->cmd->mem, sizeof(*mda)))) {
271		log_error("Unable to allocate metadata area structure "
272			  "for pool format");
273		dm_pool_free(fmt->cmd->mem, fid);
274		return NULL;
275	}
276
277	mda->ops = &_metadata_format_pool_ops;
278	mda->metadata_locn = NULL;
279	dm_list_add(&fid->metadata_areas, &mda->list);
280
281	return fid;
282}
283
284static void _pool_destroy_instance(struct format_instance *fid __attribute((unused)))
285{
286	return;
287}
288
289static void _pool_destroy(const struct format_type *fmt)
290{
291	dm_free((void *) fmt);
292}
293
294/* *INDENT-OFF* */
295static struct format_handler _format_pool_ops = {
296	.pv_read = _pool_pv_read,
297	.pv_setup = _pool_pv_setup,
298	.create_instance = _pool_create_instance,
299	.destroy_instance = _pool_destroy_instance,
300	.destroy = _pool_destroy,
301};
302/* *INDENT-ON */
303
304#ifdef POOL_INTERNAL
305struct format_type *init_pool_format(struct cmd_context *cmd)
306#else				/* Shared */
307struct format_type *init_format(struct cmd_context *cmd);
308struct format_type *init_format(struct cmd_context *cmd)
309#endif
310{
311	struct format_type *fmt = dm_malloc(sizeof(*fmt));
312
313	if (!fmt) {
314		log_error("Unable to allocate format type structure for pool "
315			  "format");
316		return NULL;
317	}
318
319	fmt->cmd = cmd;
320	fmt->ops = &_format_pool_ops;
321	fmt->name = FMT_POOL_NAME;
322	fmt->alias = NULL;
323	fmt->orphan_vg_name = FMT_POOL_ORPHAN_VG_NAME;
324	fmt->features = 0;
325	fmt->private = NULL;
326
327	if (!(fmt->labeller = pool_labeller_create(fmt))) {
328		log_error("Couldn't create pool label handler.");
329		return NULL;
330	}
331
332	if (!(label_register_handler(FMT_POOL_NAME, fmt->labeller))) {
333		log_error("Couldn't register pool label handler.");
334		return NULL;
335	}
336
337	log_very_verbose("Initialised format: %s", fmt->name);
338
339	return fmt;
340}
341