?? ldm.c
字號:
if (err != 1) printk(LDM_CRIT "First and third TOCBLOCKs don't match.\n"); else ldm_debug("Validated TOCBLOCKs successfully.\n");out: kfree(toc2); kfree(toc3); kfree(toc4); return err;no_mem: printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");err_out: err = -1; goto out;}/** * compare_privheads - compare two privheads * @ph1: first privhead * @ph2: second privhead * * This compares the two privheads @ph1 and @ph2. * * Return 1 if @ph1 and @ph2 are equal and -1 otherwise. */static int compare_privheads(const struct privhead *ph1, const struct privhead *ph2){ if ((ph1->ver_major == ph2->ver_major) && (ph1->ver_minor == ph2->ver_minor) && (ph1->logical_disk_start == ph2->logical_disk_start) && (ph1->logical_disk_size == ph2->logical_disk_size) && (ph1->config_start == ph2->config_start) && (ph1->config_size == ph2->config_size) && !strncmp(ph1->disk_id, ph2->disk_id, sizeof(ph1->disk_id))) return 1; return -1;}/** * validate_privheads - compare the privhead backups to the first one * @dev: partition device holding the LDM database * @ph1: first privhead which we have already validated before * * We already have one privhead from the beginning of the disk. * Now we compare the two other copies for safety. * * Return 1 on succes and -1 on error. */static int validate_privheads(struct block_device *bdev, const struct privhead *ph1, unsigned long base){ Sector sect; unsigned char *data; struct privhead *ph2 = NULL, *ph3 = NULL; int err; ph2 = (struct privhead*)kmalloc(sizeof(*ph2), GFP_KERNEL); if (!ph2) goto no_mem; ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL); if (!ph3) goto no_mem; data = read_dev_sector(bdev, base + OFF_PRIVHEAD2 * 2, §); if (!data) { printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n"); goto err_out; } err = parse_privhead(data, ph2); put_dev_sector(sect); if (err != 1) goto out; data = read_dev_sector(bdev, base + OFF_PRIVHEAD3 * 2 + 1, §); if (!data) { printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n"); goto err_out; } err = parse_privhead(data, ph3); put_dev_sector(sect); if (err != 1) goto out; err = compare_privheads(ph1, ph2); if (err != 1) { printk(LDM_CRIT "First and second PRIVHEADs don't match.\n"); goto out; } err = compare_privheads(ph1, ph3); if (err != 1) printk(LDM_CRIT "First and third PRIVHEADs don't match.\n"); else /* We _could_ have checked more. */ ldm_debug("Validated PRIVHEADs successfully.\n");out: kfree(ph2); kfree(ph3); return err;no_mem: printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");err_out: err = -1; goto out;}/** * create_partition - validate input and create a kernel partition device * @hd: gendisk structure in which to create partition * @minor: minor number for device to create * @start: starting offset of the partition into the parent device * @size: size of the partition * * This validates the range, then puts an entry into the kernel's partition * table. * * @start and @size are numbers of sectors. * * Return 1 on succes and -1 on error. */static int create_partition(struct gendisk *hd, const int minor, const int start, const int size){ int disk_minor; if (!hd->part) return -1; /* * Get the minor number of the parent device so we can check we don't * go beyond the end of the device. */ disk_minor = (minor >> hd->minor_shift) << hd->minor_shift; if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) { printk(LDM_CRIT "LDM Partition exceeds physical disk. " "Aborting.\n"); return -1; } add_gd_partition(hd, minor, start, size); ldm_debug("Created partition successfully.\n"); return 1;}/** * parse_privhead - parse the LDM database PRIVHEAD structure * @buffer: LDM database privhead structure loaded from the device * @ph: in memory privhead structure to return parsed information in * * This parses the LDM database PRIVHEAD structure supplied in @buffer and * sets up the in memory privhead structure @ph with the obtained information. * * Return 1 on succes and -1 on error, in which case @ph is undefined. */static int parse_privhead(const u8 *buffer, struct privhead *ph){ if (MAGIC_PRIVHEAD != BE64(buffer)) { printk(LDM_ERR "Cannot find PRIVHEAD structure. LDM database " "is corrupt. Aborting.\n"); return -1; } ph->ver_major = BE16(buffer + 0x000C); ph->ver_minor = BE16(buffer + 0x000E); if ((ph->ver_major != 2) || (ph->ver_minor != 11)) { printk(LDM_ERR "Expected PRIVHEAD version %d.%d, got %d.%d. " "Aborting.\n", 2, 11, ph->ver_major, ph->ver_minor); return -1; } ph->config_start = BE64(buffer + 0x012B); ph->config_size = BE64(buffer + 0x0133); if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */ printk(LDM_ERR "Database should be %u bytes, claims to be %Lu " "bytes. Aborting.\n", LDM_DB_SIZE, ph->config_size); return -1; } ph->logical_disk_start = BE64(buffer + 0x011B); ph->logical_disk_size = BE64(buffer + 0x0123); if (!ph->logical_disk_size || ph->logical_disk_start + ph->logical_disk_size > ph->config_start) return -1; memcpy(ph->disk_id, buffer + 0x0030, sizeof(ph->disk_id)); ldm_debug("Parsed PRIVHEAD successfully.\n"); return 1;}/** * create_db_partition - create a dedicated partition for our database * @hd: gendisk structure in which to create partition * @dev: device of which to create partition * @ph: @dev's LDM database private header * * Find the primary private header, locate the LDM database, then create a * partition to wrap it. * * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error. */static int create_db_partition(struct gendisk *hd, struct block_device *bdev, const unsigned long first_sector, const int first_part_minor, struct privhead *ph){ Sector sect; unsigned char *data; int err; data = read_dev_sector(bdev, OFF_PRIVHEAD1*2, §); if (!data) { printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n"); return -1; } if (BE64(data) != MAGIC_PRIVHEAD) { ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk " "or corrupt LDM database.\n"); return 0; } err = parse_privhead(data, ph); if (err == 1) err = create_partition(hd, first_part_minor, first_sector + ph->config_start, ph->config_size); put_dev_sector(sect); return err;}/** * validate_patition_table - check whether @dev is a dynamic disk * @dev: device to test * * Check whether @dev is a dynamic disk by looking for an MS-DOS-style partition * table with one or more entries of type 0x42 (the former Secure File System * (Landis) partition type, now recycled by Microsoft for dynamic disks) in it. * If this succeeds we assume we have a dynamic disk, and not otherwise. * * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error. */static int validate_partition_table(struct block_device *bdev){ Sector sect; unsigned char *data; struct partition *p; int i, nr_sfs; data = read_dev_sector(bdev, 0, §); if (!data) return -1; if (*(u16*)(data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { ldm_debug("No MS-DOS partition found.\n"); goto no_msdos_partition; } nr_sfs = 0; p = (struct partition*)(data + 0x01BE); for (i = 0; i < 4; i++) { if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION) continue; if (SYS_IND(p+i) == WIN2K_DYNAMIC_PARTITION) { nr_sfs++; continue; } goto not_dynamic_disk; } if (!nr_sfs) goto not_dynamic_disk; ldm_debug("Parsed partition table successfully.\n"); put_dev_sector(sect); return 1;not_dynamic_disk:// ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");no_msdos_partition: put_dev_sector(sect); return 0;}/** * ldm_partition - find out whether a device is a dynamic disk and handle it * @hd: gendisk structure in which to return the handled disk * @dev: device we need to look at * @first_sector: first sector within the device * @first_part_minor: first minor number of partitions for the device * * Description: * * This determines whether the device @dev 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, we skip * devices 2-4 and then create each partition described by the LDM database * in sequence as devices 5 and following. For example, if the device is hda, * we would have: hda1: LDM database, hda2-4: nothing, hda5-following: the * actual data containing partitions. * * Return values: * * 1 if @dev is a dynamic disk and we handled it, * 0 if @dev is not a dynamic disk, * -1 if an error occured. */int ldm_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor){ struct privhead *ph = NULL; struct tocblock *toc = NULL; struct vmdb *vm = NULL; struct ldmdisk *dk = NULL; unsigned long db_first; int err; if (!hd) return 0; /* Check the partition table. */ err = validate_partition_table(bdev); if (err != 1) return err; if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL))) goto no_mem; /* Create the LDM database device. */ err = create_db_partition(hd, bdev, first_sector, first_part_minor, ph); if (err != 1) goto out; db_first = hd->part[first_part_minor].start_sect; /* Check the backup privheads. */ err = validate_privheads(bdev, ph, db_first); if (err != 1) goto out; /* Check the table of contents and its backups. */ if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL))) goto no_mem; err = validate_tocblocks(bdev, toc, db_first); if (err != 1) goto out; /* Check the vmdb. */ if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL))) goto no_mem; err = validate_vmdb(bdev, vm, db_first); if (err != 1) goto out; /* Find the object id for @dev in the LDM database. */ if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL))) goto no_mem; err = get_disk_objid(bdev, vm, ph, dk, db_first); if (err != 1) goto out; /* Finally, create the data partition devices. */ err = create_data_partitions(hd, first_sector, first_part_minor + LDM_FIRST_PART_OFFSET, bdev, vm, ph, dk, db_first); if (err == 1) ldm_debug("Parsed LDM database successfully.\n");out: kfree(ph); kfree(toc); kfree(vm); kfree(dk); return err;no_mem: printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); err = -1; goto out;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -