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

📄 ldm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (len > BE32(buffer + 0x14)) {		ldm_error("len %d > BE32(buffer + 0x14) %d", len,				BE32(buffer + 0x14));		return false;	}	part = &vb->vblk.part;	part->start = BE64(buffer + 0x24 + r_name);	part->volume_offset = BE64(buffer + 0x2C + r_name);	part->size = ldm_get_vnum(buffer + 0x34 + r_name);	part->parent_id = ldm_get_vnum(buffer + 0x34 + r_size);	part->disk_id = ldm_get_vnum(buffer + 0x34 + r_parent);	if (vb->flags & VBLK_FLAG_PART_INDEX)		part->partnum = buffer[0x35 + r_diskid];	else		part->partnum = 0;	return true;}/** * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure * @buffer:  Block of data being worked on * @buflen:  Size of the block of data * @vb:      In-memory vblk in which to return information * * Read a raw VBLK Volume object (version 5) into a vblk structure. * * Return:  'true'   @vb contains a Volume VBLK *          'false'  @vb contents are not defined */static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb){	int r_objid, r_name, r_vtype, r_disable_drive_letter, r_child, r_size;	int r_id1, r_id2, r_size2, r_drive, len;	struct vblk_volu *volu;	BUG_ON(!buffer || !vb);	r_objid = ldm_relative(buffer, buflen, 0x18, 0);	if (r_objid < 0) {		ldm_error("r_objid %d < 0", r_objid);		return false;	}	r_name = ldm_relative(buffer, buflen, 0x18, r_objid);	if (r_name < 0) {		ldm_error("r_name %d < 0", r_name);		return false;	}	r_vtype = ldm_relative(buffer, buflen, 0x18, r_name);	if (r_vtype < 0) {		ldm_error("r_vtype %d < 0", r_vtype);		return false;	}	r_disable_drive_letter = ldm_relative(buffer, buflen, 0x18, r_vtype);	if (r_disable_drive_letter < 0) {		ldm_error("r_disable_drive_letter %d < 0",				r_disable_drive_letter);		return false;	}	r_child = ldm_relative(buffer, buflen, 0x2D, r_disable_drive_letter);	if (r_child < 0) {		ldm_error("r_child %d < 0", r_child);		return false;	}	r_size = ldm_relative(buffer, buflen, 0x3D, r_child);	if (r_size < 0) {		ldm_error("r_size %d < 0", r_size);		return false;	}	if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) {		r_id1 = ldm_relative(buffer, buflen, 0x52, r_size);		if (r_id1 < 0) {			ldm_error("r_id1 %d < 0", r_id1);			return false;		}	} else		r_id1 = r_size;	if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) {		r_id2 = ldm_relative(buffer, buflen, 0x52, r_id1);		if (r_id2 < 0) {			ldm_error("r_id2 %d < 0", r_id2);			return false;		}	} else		r_id2 = r_id1;	if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) {		r_size2 = ldm_relative(buffer, buflen, 0x52, r_id2);		if (r_size2 < 0) {			ldm_error("r_size2 %d < 0", r_size2);			return false;		}	} else		r_size2 = r_id2;	if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {		r_drive = ldm_relative(buffer, buflen, 0x52, r_size2);		if (r_drive < 0) {			ldm_error("r_drive %d < 0", r_drive);			return false;		}	} else		r_drive = r_size2;	len = r_drive;	if (len < 0) {		ldm_error("len %d < 0", len);		return false;	}	len += VBLK_SIZE_VOL5;	if (len > BE32(buffer + 0x14)) {		ldm_error("len %d > BE32(buffer + 0x14) %d", len,				BE32(buffer + 0x14));		return false;	}	volu = &vb->vblk.volu;	ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type,			sizeof(volu->volume_type));	memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter,			sizeof(volu->volume_state));	volu->size = ldm_get_vnum(buffer + 0x3D + r_child);	volu->partition_type = buffer[0x41 + r_size];	memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid));	if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {		ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint,				sizeof(volu->drive_hint));	}	return true;}/** * ldm_parse_vblk - Read a raw VBLK object into a vblk structure * @buf:  Block of data being worked on * @len:  Size of the block of data * @vb:   In-memory vblk in which to return information * * Read a raw VBLK object into a vblk structure.  This function just reads the * information common to all VBLK types, then delegates the rest of the work to * helper functions: ldm_parse_*. * * Return:  'true'   @vb contains a VBLK *          'false'  @vb contents are not defined */static bool ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb){	bool result = false;	int r_objid;	BUG_ON (!buf || !vb);	r_objid = ldm_relative (buf, len, 0x18, 0);	if (r_objid < 0) {		ldm_error ("VBLK header is corrupt.");		return false;	}	vb->flags  = buf[0x12];	vb->type   = buf[0x13];	vb->obj_id = ldm_get_vnum (buf + 0x18);	ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name));	switch (vb->type) {		case VBLK_CMP3:  result = ldm_parse_cmp3 (buf, len, vb); break;		case VBLK_DSK3:  result = ldm_parse_dsk3 (buf, len, vb); break;		case VBLK_DSK4:  result = ldm_parse_dsk4 (buf, len, vb); break;		case VBLK_DGR3:  result = ldm_parse_dgr3 (buf, len, vb); break;		case VBLK_DGR4:  result = ldm_parse_dgr4 (buf, len, vb); break;		case VBLK_PRT3:  result = ldm_parse_prt3 (buf, len, vb); break;		case VBLK_VOL5:  result = ldm_parse_vol5 (buf, len, vb); break;	}	if (result)		ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.",			 (unsigned long long) vb->obj_id, vb->type);	else		ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).",			(unsigned long long) vb->obj_id, vb->type);	return result;}/** * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database * @data:  Raw VBLK to add to the database * @len:   Size of the raw VBLK * @ldb:   Cache of the database structures * * The VBLKs are sorted into categories.  Partitions are also sorted by offset. * * N.B.  This function does not check the validity of the VBLKs. * * Return:  'true'   The VBLK was added *          'false'  An error occurred */static bool ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb){	struct vblk *vb;	struct list_head *item;	BUG_ON (!data || !ldb);	vb = kmalloc (sizeof (*vb), GFP_KERNEL);	if (!vb) {		ldm_crit ("Out of memory.");		return false;	}	if (!ldm_parse_vblk (data, len, vb)) {		kfree(vb);		return false;			/* Already logged */	}	/* Put vblk into the correct list. */	switch (vb->type) {	case VBLK_DGR3:	case VBLK_DGR4:		list_add (&vb->list, &ldb->v_dgrp);		break;	case VBLK_DSK3:	case VBLK_DSK4:		list_add (&vb->list, &ldb->v_disk);		break;	case VBLK_VOL5:		list_add (&vb->list, &ldb->v_volu);		break;	case VBLK_CMP3:		list_add (&vb->list, &ldb->v_comp);		break;	case VBLK_PRT3:		/* Sort by the partition's start sector. */		list_for_each (item, &ldb->v_part) {			struct vblk *v = list_entry (item, struct vblk, list);			if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&			    (v->vblk.part.start > vb->vblk.part.start)) {				list_add_tail (&vb->list, &v->list);				return true;			}		}		list_add_tail (&vb->list, &ldb->v_part);		break;	}	return true;}/** * ldm_frag_add - Add a VBLK fragment to a list * @data:   Raw fragment to be added to the list * @size:   Size of the raw fragment * @frags:  Linked list of VBLK fragments * * Fragmented VBLKs may not be consecutive in the database, so they are placed * in a list so they can be pieced together later. * * Return:  'true'   Success, the VBLK was added to the list *          'false'  Error, a problem occurred */static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags){	struct frag *f;	struct list_head *item;	int rec, num, group;	BUG_ON (!data || !frags);	group = BE32 (data + 0x08);	rec   = BE16 (data + 0x0C);	num   = BE16 (data + 0x0E);	if ((num < 1) || (num > 4)) {		ldm_error ("A VBLK claims to have %d parts.", num);		return false;	}	list_for_each (item, frags) {		f = list_entry (item, struct frag, list);		if (f->group == group)			goto found;	}	f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);	if (!f) {		ldm_crit ("Out of memory.");		return false;	}	f->group = group;	f->num   = num;	f->rec   = rec;	f->map   = 0xFF << num;	list_add_tail (&f->list, frags);found:	if (f->map & (1 << rec)) {		ldm_error ("Duplicate VBLK, part %d.", rec);		f->map &= 0x7F;			/* Mark the group as broken */		return false;	}	f->map |= (1 << rec);	if (num > 0) {		data += VBLK_SIZE_HEAD;		size -= VBLK_SIZE_HEAD;	}	memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);	return true;}/** * ldm_frag_free - Free a linked list of VBLK fragments * @list:  Linked list of fragments * * Free a linked list of VBLK fragments * * Return:  none */static void ldm_frag_free (struct list_head *list){	struct list_head *item, *tmp;	BUG_ON (!list);	list_for_each_safe (item, tmp, list)		kfree (list_entry (item, struct frag, list));}/** * ldm_frag_commit - Validate fragmented VBLKs and add them to the database * @frags:  Linked list of VBLK fragments * @ldb:    Cache of the database structures * * Now that all the fragmented VBLKs have been collected, they must be added to * the database for later use. * * Return:  'true'   All the fragments we added successfully *          'false'  One or more of the fragments we invalid */static bool ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb){	struct frag *f;	struct list_head *item;	BUG_ON (!frags || !ldb);	list_for_each (item, frags) {		f = list_entry (item, struct frag, list);		if (f->map != 0xFF) {			ldm_error ("VBLK group %d is incomplete (0x%02x).",				f->group, f->map);			return false;		}		if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))			return false;		/* Already logged */	}	return true;}/** * ldm_get_vblks - Read the on-disk database of VBLKs into memory * @bdev:  Device holding the LDM Database * @base:  Offset, into @bdev, of the database * @ldb:   Cache of the database structures * * To use the information from the VBLKs, they need to be read from the disk, * unpacked and validated.  We cache them in @ldb according to their type. * * Return:  'true'   All the VBLKs were read successfully *          'false'  An error occurred */static bool ldm_get_vblks (struct block_device *bdev, unsigned long base,			   struct ldmdb *ldb){	int size, perbuf, skip, finish, s, v, recs;	u8 *data = NULL;	Sector sect;	bool result = false;	LIST_HEAD (frags);	BUG_ON (!bdev || !ldb);	size   = ldb->vm.vblk_size;	perbuf = 512 / size;	skip   = ldb->vm.vblk_offset >> 9;		/* Bytes to sectors */	finish = (size * ldb->vm.last_vblk_seq) >> 9;	for (s = skip; s < finish; s++) {		/* For each sector */		data = read_dev_sector (bdev, base + OFF_VMDB + s, &sect);		if (!data) {			ldm_crit ("Disk read failed.");			goto out;		}		for (v = 0; v < perbuf; v++, data+=size) {  /* For each vblk */			if (MAGIC_VBLK != BE32 (data)) {				ldm_error ("Expected to find a VBLK.");				goto out;			}			recs = BE16 (data + 0x0E);	/* Number of records */			if (recs == 1) {				if (!ldm_ldmdb_add (data, size, ldb))					goto out;	/* Already logged */			} else if (recs > 1) {				if (!ldm_frag_add (data, size, &frags))					goto out;	/* Already logged */			}			/* else Record is not in use, ignore it. */		}		put_dev_sector (sect);		data = NULL;	}	result = ldm_frag_commit (&frags, ldb);	/* Failures, already logged */out:	if (data)		put_dev_sector (sect);	ldm_frag_free (&frags);	return result;}/** * ldm_free_vblks - Free a linked list of vblk's * @lh:  Head of a linked list of struct vblk * * Free a list of vblk's and free the memory used to maintain the list. * * Return:  none */static void ldm_free_vblks (struct list_head *lh){	struct list_head *item, *tmp;	BUG_ON (!lh);	list_for_each_safe (item, tmp, lh)		kfree (list_entry (item, struct vblk, list));}/** * ldm_partition - Find out whether a device is a dynamic disk and handle it * @pp:    List of the partitions parsed so far * @bdev:  Device holding the LDM Database * * This determines whether the device @bdev is a dynamic disk and if so creates * the partitions necessary in the gendisk structure pointed to by @hd. * * We create a dummy device 1, which contains the LDM database, and then create * each partition described by the LDM database in sequence as devices 2+. For * example, if the device is hda, we would have: hda1: LDM database, hda2, hda3, * and so on: the actual data containing partitions. * * Return:  1 Success, @bdev is a dynamic disk and we handled it *          0 Success, @bdev is not a dynamic disk *         -1 An error occurred before enough information had been read *            Or @bdev is a dynamic disk, but it may be corrupted */int ldm_partition (struct parsed_partitions *pp, struct block_device *bdev){	struct ldmdb  *ldb;	unsigned long base;	int result = -1;	BUG_ON (!pp || !bdev);	/* Look for signs of a Dynamic Disk */	if (!ldm_validate_partition_table (bdev))		return 0;	ldb = kmalloc (sizeof (*ldb), GFP_KERNEL);	if (!ldb) {		ldm_crit ("Out of memory.");		goto out;	}	/* Parse and check privheads. */	if (!ldm_validate_privheads (bdev, &ldb->ph))		goto out;		/* Already logged */	/* All further references are relative to base (database start). */	base = ldb->ph.config_start;	/* Parse and check tocs and vmdb. */	if (!ldm_validate_tocblocks (bdev, base, ldb) ||	    !ldm_validate_vmdb      (bdev, base, ldb))	    	goto out;		/* Already logged */	/* Initialize vblk lists in ldmdb struct */	INIT_LIST_HEAD (&ldb->v_dgrp);	INIT_LIST_HEAD (&ldb->v_disk);	INIT_LIST_HEAD (&ldb->v_volu);	INIT_LIST_HEAD (&ldb->v_comp);	INIT_LIST_HEAD (&ldb->v_part);	if (!ldm_get_vblks (bdev, base, ldb)) {		ldm_crit ("Failed to read the VBLKs from the database.");		goto cleanup;	}	/* Finally, create the data partition devices. */	if (ldm_create_data_partitions (pp, ldb)) {		ldm_debug ("Parsed LDM database successfully.");		result = 1;	}	/* else Already logged */cleanup:	ldm_free_vblks (&ldb->v_dgrp);	ldm_free_vblks (&ldb->v_disk);	ldm_free_vblks (&ldb->v_volu);	ldm_free_vblks (&ldb->v_comp);	ldm_free_vblks (&ldb->v_part);out:	kfree (ldb);	return result;}

⌨️ 快捷键说明

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