16ceea22bSPhilippe De Muyter /* 26ceea22bSPhilippe De Muyter * fs/partitions/aix.c 36ceea22bSPhilippe De Muyter * 46ceea22bSPhilippe De Muyter * Copyright (C) 2012-2013 Philippe De Muyter <phdm@macqel.be> 56ceea22bSPhilippe De Muyter */ 66ceea22bSPhilippe De Muyter 76ceea22bSPhilippe De Muyter #include "check.h" 86ceea22bSPhilippe De Muyter #include "aix.h" 96ceea22bSPhilippe De Muyter 106ceea22bSPhilippe De Muyter struct lvm_rec { 116ceea22bSPhilippe De Muyter char lvm_id[4]; /* "_LVM" */ 126ceea22bSPhilippe De Muyter char reserved4[16]; 136ceea22bSPhilippe De Muyter __be32 lvmarea_len; 146ceea22bSPhilippe De Muyter __be32 vgda_len; 156ceea22bSPhilippe De Muyter __be32 vgda_psn[2]; 166ceea22bSPhilippe De Muyter char reserved36[10]; 176ceea22bSPhilippe De Muyter __be16 pp_size; /* log2(pp_size) */ 186ceea22bSPhilippe De Muyter char reserved46[12]; 196ceea22bSPhilippe De Muyter __be16 version; 206ceea22bSPhilippe De Muyter }; 216ceea22bSPhilippe De Muyter 226ceea22bSPhilippe De Muyter struct vgda { 236ceea22bSPhilippe De Muyter __be32 secs; 246ceea22bSPhilippe De Muyter __be32 usec; 256ceea22bSPhilippe De Muyter char reserved8[16]; 266ceea22bSPhilippe De Muyter __be16 numlvs; 276ceea22bSPhilippe De Muyter __be16 maxlvs; 286ceea22bSPhilippe De Muyter __be16 pp_size; 296ceea22bSPhilippe De Muyter __be16 numpvs; 306ceea22bSPhilippe De Muyter __be16 total_vgdas; 316ceea22bSPhilippe De Muyter __be16 vgda_size; 326ceea22bSPhilippe De Muyter }; 336ceea22bSPhilippe De Muyter 346ceea22bSPhilippe De Muyter struct lvd { 356ceea22bSPhilippe De Muyter __be16 lv_ix; 366ceea22bSPhilippe De Muyter __be16 res2; 376ceea22bSPhilippe De Muyter __be16 res4; 386ceea22bSPhilippe De Muyter __be16 maxsize; 396ceea22bSPhilippe De Muyter __be16 lv_state; 406ceea22bSPhilippe De Muyter __be16 mirror; 416ceea22bSPhilippe De Muyter __be16 mirror_policy; 426ceea22bSPhilippe De Muyter __be16 num_lps; 436ceea22bSPhilippe De Muyter __be16 res10[8]; 446ceea22bSPhilippe De Muyter }; 456ceea22bSPhilippe De Muyter 466ceea22bSPhilippe De Muyter struct lvname { 476ceea22bSPhilippe De Muyter char name[64]; 486ceea22bSPhilippe De Muyter }; 496ceea22bSPhilippe De Muyter 506ceea22bSPhilippe De Muyter struct ppe { 516ceea22bSPhilippe De Muyter __be16 lv_ix; 526ceea22bSPhilippe De Muyter unsigned short res2; 536ceea22bSPhilippe De Muyter unsigned short res4; 546ceea22bSPhilippe De Muyter __be16 lp_ix; 556ceea22bSPhilippe De Muyter unsigned short res8[12]; 566ceea22bSPhilippe De Muyter }; 576ceea22bSPhilippe De Muyter 586ceea22bSPhilippe De Muyter struct pvd { 596ceea22bSPhilippe De Muyter char reserved0[16]; 606ceea22bSPhilippe De Muyter __be16 pp_count; 616ceea22bSPhilippe De Muyter char reserved18[2]; 626ceea22bSPhilippe De Muyter __be32 psn_part1; 636ceea22bSPhilippe De Muyter char reserved24[8]; 646ceea22bSPhilippe De Muyter struct ppe ppe[1016]; 656ceea22bSPhilippe De Muyter }; 666ceea22bSPhilippe De Muyter 676ceea22bSPhilippe De Muyter #define LVM_MAXLVS 256 686ceea22bSPhilippe De Muyter 696ceea22bSPhilippe De Muyter /** 706ceea22bSPhilippe De Muyter * last_lba(): return number of last logical block of device 716ceea22bSPhilippe De Muyter * @bdev: block device 726ceea22bSPhilippe De Muyter * 736ceea22bSPhilippe De Muyter * Description: Returns last LBA value on success, 0 on error. 746ceea22bSPhilippe De Muyter * This is stored (by sd and ide-geometry) in 756ceea22bSPhilippe De Muyter * the part[0] entry for this disk, and is the number of 766ceea22bSPhilippe De Muyter * physical sectors available on the disk. 776ceea22bSPhilippe De Muyter */ 786ceea22bSPhilippe De Muyter static u64 last_lba(struct block_device *bdev) 796ceea22bSPhilippe De Muyter { 806ceea22bSPhilippe De Muyter if (!bdev || !bdev->bd_inode) 816ceea22bSPhilippe De Muyter return 0; 826ceea22bSPhilippe De Muyter return (bdev->bd_inode->i_size >> 9) - 1ULL; 836ceea22bSPhilippe De Muyter } 846ceea22bSPhilippe De Muyter 856ceea22bSPhilippe De Muyter /** 866ceea22bSPhilippe De Muyter * read_lba(): Read bytes from disk, starting at given LBA 876ceea22bSPhilippe De Muyter * @state 886ceea22bSPhilippe De Muyter * @lba 896ceea22bSPhilippe De Muyter * @buffer 906ceea22bSPhilippe De Muyter * @count 916ceea22bSPhilippe De Muyter * 926ceea22bSPhilippe De Muyter * Description: Reads @count bytes from @state->bdev into @buffer. 936ceea22bSPhilippe De Muyter * Returns number of bytes read on success, 0 on error. 946ceea22bSPhilippe De Muyter */ 956ceea22bSPhilippe De Muyter static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer, 966ceea22bSPhilippe De Muyter size_t count) 976ceea22bSPhilippe De Muyter { 986ceea22bSPhilippe De Muyter size_t totalreadcount = 0; 996ceea22bSPhilippe De Muyter 1006ceea22bSPhilippe De Muyter if (!buffer || lba + count / 512 > last_lba(state->bdev)) 1016ceea22bSPhilippe De Muyter return 0; 1026ceea22bSPhilippe De Muyter 1036ceea22bSPhilippe De Muyter while (count) { 1046ceea22bSPhilippe De Muyter int copied = 512; 1056ceea22bSPhilippe De Muyter Sector sect; 1066ceea22bSPhilippe De Muyter unsigned char *data = read_part_sector(state, lba++, §); 1076ceea22bSPhilippe De Muyter if (!data) 1086ceea22bSPhilippe De Muyter break; 1096ceea22bSPhilippe De Muyter if (copied > count) 1106ceea22bSPhilippe De Muyter copied = count; 1116ceea22bSPhilippe De Muyter memcpy(buffer, data, copied); 1126ceea22bSPhilippe De Muyter put_dev_sector(sect); 1136ceea22bSPhilippe De Muyter buffer += copied; 1146ceea22bSPhilippe De Muyter totalreadcount += copied; 1156ceea22bSPhilippe De Muyter count -= copied; 1166ceea22bSPhilippe De Muyter } 1176ceea22bSPhilippe De Muyter return totalreadcount; 1186ceea22bSPhilippe De Muyter } 1196ceea22bSPhilippe De Muyter 1206ceea22bSPhilippe De Muyter /** 1216ceea22bSPhilippe De Muyter * alloc_pvd(): reads physical volume descriptor 1226ceea22bSPhilippe De Muyter * @state 1236ceea22bSPhilippe De Muyter * @lba 1246ceea22bSPhilippe De Muyter * 1256ceea22bSPhilippe De Muyter * Description: Returns pvd on success, NULL on error. 1266ceea22bSPhilippe De Muyter * Allocates space for pvd and fill it with disk blocks at @lba 1276ceea22bSPhilippe De Muyter * Notes: remember to free pvd when you're done! 1286ceea22bSPhilippe De Muyter */ 1296ceea22bSPhilippe De Muyter static struct pvd *alloc_pvd(struct parsed_partitions *state, u32 lba) 1306ceea22bSPhilippe De Muyter { 1316ceea22bSPhilippe De Muyter size_t count = sizeof(struct pvd); 1326ceea22bSPhilippe De Muyter struct pvd *p; 1336ceea22bSPhilippe De Muyter 1346ceea22bSPhilippe De Muyter p = kmalloc(count, GFP_KERNEL); 1356ceea22bSPhilippe De Muyter if (!p) 1366ceea22bSPhilippe De Muyter return NULL; 1376ceea22bSPhilippe De Muyter 1386ceea22bSPhilippe De Muyter if (read_lba(state, lba, (u8 *) p, count) < count) { 1396ceea22bSPhilippe De Muyter kfree(p); 1406ceea22bSPhilippe De Muyter return NULL; 1416ceea22bSPhilippe De Muyter } 1426ceea22bSPhilippe De Muyter return p; 1436ceea22bSPhilippe De Muyter } 1446ceea22bSPhilippe De Muyter 1456ceea22bSPhilippe De Muyter /** 1466ceea22bSPhilippe De Muyter * alloc_lvn(): reads logical volume names 1476ceea22bSPhilippe De Muyter * @state 1486ceea22bSPhilippe De Muyter * @lba 1496ceea22bSPhilippe De Muyter * 1506ceea22bSPhilippe De Muyter * Description: Returns lvn on success, NULL on error. 1516ceea22bSPhilippe De Muyter * Allocates space for lvn and fill it with disk blocks at @lba 1526ceea22bSPhilippe De Muyter * Notes: remember to free lvn when you're done! 1536ceea22bSPhilippe De Muyter */ 1546ceea22bSPhilippe De Muyter static struct lvname *alloc_lvn(struct parsed_partitions *state, u32 lba) 1556ceea22bSPhilippe De Muyter { 1566ceea22bSPhilippe De Muyter size_t count = sizeof(struct lvname) * LVM_MAXLVS; 1576ceea22bSPhilippe De Muyter struct lvname *p; 1586ceea22bSPhilippe De Muyter 1596ceea22bSPhilippe De Muyter p = kmalloc(count, GFP_KERNEL); 1606ceea22bSPhilippe De Muyter if (!p) 1616ceea22bSPhilippe De Muyter return NULL; 1626ceea22bSPhilippe De Muyter 1636ceea22bSPhilippe De Muyter if (read_lba(state, lba, (u8 *) p, count) < count) { 1646ceea22bSPhilippe De Muyter kfree(p); 1656ceea22bSPhilippe De Muyter return NULL; 1666ceea22bSPhilippe De Muyter } 1676ceea22bSPhilippe De Muyter return p; 1686ceea22bSPhilippe De Muyter } 1696ceea22bSPhilippe De Muyter 1706ceea22bSPhilippe De Muyter int aix_partition(struct parsed_partitions *state) 1716ceea22bSPhilippe De Muyter { 1726ceea22bSPhilippe De Muyter int ret = 0; 1736ceea22bSPhilippe De Muyter Sector sect; 1746ceea22bSPhilippe De Muyter unsigned char *d; 1756ceea22bSPhilippe De Muyter u32 pp_bytes_size; 1766ceea22bSPhilippe De Muyter u32 pp_blocks_size = 0; 1776ceea22bSPhilippe De Muyter u32 vgda_sector = 0; 1786ceea22bSPhilippe De Muyter u32 vgda_len = 0; 1796ceea22bSPhilippe De Muyter int numlvs = 0; 1806ceea22bSPhilippe De Muyter struct pvd *pvd; 1816ceea22bSPhilippe De Muyter struct lv_info { 1826ceea22bSPhilippe De Muyter unsigned short pps_per_lv; 1836ceea22bSPhilippe De Muyter unsigned short pps_found; 1846ceea22bSPhilippe De Muyter unsigned char lv_is_contiguous; 1856ceea22bSPhilippe De Muyter } *lvip; 1866ceea22bSPhilippe De Muyter struct lvname *n = NULL; 1876ceea22bSPhilippe De Muyter 1886ceea22bSPhilippe De Muyter d = read_part_sector(state, 7, §); 1896ceea22bSPhilippe De Muyter if (d) { 1906ceea22bSPhilippe De Muyter struct lvm_rec *p = (struct lvm_rec *)d; 1916ceea22bSPhilippe De Muyter u16 lvm_version = be16_to_cpu(p->version); 1926ceea22bSPhilippe De Muyter char tmp[64]; 1936ceea22bSPhilippe De Muyter 1946ceea22bSPhilippe De Muyter if (lvm_version == 1) { 1956ceea22bSPhilippe De Muyter int pp_size_log2 = be16_to_cpu(p->pp_size); 1966ceea22bSPhilippe De Muyter 1976ceea22bSPhilippe De Muyter pp_bytes_size = 1 << pp_size_log2; 1986ceea22bSPhilippe De Muyter pp_blocks_size = pp_bytes_size / 512; 1996ceea22bSPhilippe De Muyter snprintf(tmp, sizeof(tmp), 2006ceea22bSPhilippe De Muyter " AIX LVM header version %u found\n", 2016ceea22bSPhilippe De Muyter lvm_version); 2026ceea22bSPhilippe De Muyter vgda_len = be32_to_cpu(p->vgda_len); 2036ceea22bSPhilippe De Muyter vgda_sector = be32_to_cpu(p->vgda_psn[0]); 2046ceea22bSPhilippe De Muyter } else { 2056ceea22bSPhilippe De Muyter snprintf(tmp, sizeof(tmp), 2066ceea22bSPhilippe De Muyter " unsupported AIX LVM version %d found\n", 2076ceea22bSPhilippe De Muyter lvm_version); 2086ceea22bSPhilippe De Muyter } 2096ceea22bSPhilippe De Muyter strlcat(state->pp_buf, tmp, PAGE_SIZE); 2106ceea22bSPhilippe De Muyter put_dev_sector(sect); 2116ceea22bSPhilippe De Muyter } 2126ceea22bSPhilippe De Muyter if (vgda_sector && (d = read_part_sector(state, vgda_sector, §))) { 2136ceea22bSPhilippe De Muyter struct vgda *p = (struct vgda *)d; 2146ceea22bSPhilippe De Muyter 2156ceea22bSPhilippe De Muyter numlvs = be16_to_cpu(p->numlvs); 2166ceea22bSPhilippe De Muyter put_dev_sector(sect); 2176ceea22bSPhilippe De Muyter } 218*472d5e2aSFabian Frederick lvip = kcalloc(state->limit, sizeof(struct lv_info), GFP_KERNEL); 2196ceea22bSPhilippe De Muyter if (!lvip) 2206ceea22bSPhilippe De Muyter return 0; 2216ceea22bSPhilippe De Muyter if (numlvs && (d = read_part_sector(state, vgda_sector + 1, §))) { 2226ceea22bSPhilippe De Muyter struct lvd *p = (struct lvd *)d; 2236ceea22bSPhilippe De Muyter int i; 2246ceea22bSPhilippe De Muyter 2256ceea22bSPhilippe De Muyter n = alloc_lvn(state, vgda_sector + vgda_len - 33); 2266ceea22bSPhilippe De Muyter if (n) { 2276ceea22bSPhilippe De Muyter int foundlvs = 0; 2286ceea22bSPhilippe De Muyter 2296ceea22bSPhilippe De Muyter for (i = 0; foundlvs < numlvs && i < state->limit; i += 1) { 2306ceea22bSPhilippe De Muyter lvip[i].pps_per_lv = be16_to_cpu(p[i].num_lps); 2316ceea22bSPhilippe De Muyter if (lvip[i].pps_per_lv) 2326ceea22bSPhilippe De Muyter foundlvs += 1; 2336ceea22bSPhilippe De Muyter } 2346ceea22bSPhilippe De Muyter } 2356ceea22bSPhilippe De Muyter put_dev_sector(sect); 2366ceea22bSPhilippe De Muyter } 2376ceea22bSPhilippe De Muyter pvd = alloc_pvd(state, vgda_sector + 17); 2386ceea22bSPhilippe De Muyter if (pvd) { 2396ceea22bSPhilippe De Muyter int numpps = be16_to_cpu(pvd->pp_count); 2406ceea22bSPhilippe De Muyter int psn_part1 = be32_to_cpu(pvd->psn_part1); 2416ceea22bSPhilippe De Muyter int i; 2426ceea22bSPhilippe De Muyter int cur_lv_ix = -1; 2436ceea22bSPhilippe De Muyter int next_lp_ix = 1; 2446ceea22bSPhilippe De Muyter int lp_ix; 2456ceea22bSPhilippe De Muyter 2466ceea22bSPhilippe De Muyter for (i = 0; i < numpps; i += 1) { 2476ceea22bSPhilippe De Muyter struct ppe *p = pvd->ppe + i; 2486ceea22bSPhilippe De Muyter unsigned int lv_ix; 2496ceea22bSPhilippe De Muyter 2506ceea22bSPhilippe De Muyter lp_ix = be16_to_cpu(p->lp_ix); 2516ceea22bSPhilippe De Muyter if (!lp_ix) { 2526ceea22bSPhilippe De Muyter next_lp_ix = 1; 2536ceea22bSPhilippe De Muyter continue; 2546ceea22bSPhilippe De Muyter } 2556ceea22bSPhilippe De Muyter lv_ix = be16_to_cpu(p->lv_ix) - 1; 2566ceea22bSPhilippe De Muyter if (lv_ix > state->limit) { 2576ceea22bSPhilippe De Muyter cur_lv_ix = -1; 2586ceea22bSPhilippe De Muyter continue; 2596ceea22bSPhilippe De Muyter } 2606ceea22bSPhilippe De Muyter lvip[lv_ix].pps_found += 1; 2616ceea22bSPhilippe De Muyter if (lp_ix == 1) { 2626ceea22bSPhilippe De Muyter cur_lv_ix = lv_ix; 2636ceea22bSPhilippe De Muyter next_lp_ix = 1; 2646ceea22bSPhilippe De Muyter } else if (lv_ix != cur_lv_ix || lp_ix != next_lp_ix) { 2656ceea22bSPhilippe De Muyter next_lp_ix = 1; 2666ceea22bSPhilippe De Muyter continue; 2676ceea22bSPhilippe De Muyter } 2686ceea22bSPhilippe De Muyter if (lp_ix == lvip[lv_ix].pps_per_lv) { 2696ceea22bSPhilippe De Muyter char tmp[70]; 2706ceea22bSPhilippe De Muyter 2716ceea22bSPhilippe De Muyter put_partition(state, lv_ix + 1, 2726ceea22bSPhilippe De Muyter (i + 1 - lp_ix) * pp_blocks_size + psn_part1, 2736ceea22bSPhilippe De Muyter lvip[lv_ix].pps_per_lv * pp_blocks_size); 2746ceea22bSPhilippe De Muyter snprintf(tmp, sizeof(tmp), " <%s>\n", 2756ceea22bSPhilippe De Muyter n[lv_ix].name); 2766ceea22bSPhilippe De Muyter strlcat(state->pp_buf, tmp, PAGE_SIZE); 2776ceea22bSPhilippe De Muyter lvip[lv_ix].lv_is_contiguous = 1; 2786ceea22bSPhilippe De Muyter ret = 1; 2796ceea22bSPhilippe De Muyter next_lp_ix = 1; 2806ceea22bSPhilippe De Muyter } else 2816ceea22bSPhilippe De Muyter next_lp_ix += 1; 2826ceea22bSPhilippe De Muyter } 2836ceea22bSPhilippe De Muyter for (i = 0; i < state->limit; i += 1) 2846ceea22bSPhilippe De Muyter if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) 2856ceea22bSPhilippe De Muyter pr_warn("partition %s (%u pp's found) is " 2866ceea22bSPhilippe De Muyter "not contiguous\n", 2876ceea22bSPhilippe De Muyter n[i].name, lvip[i].pps_found); 2886ceea22bSPhilippe De Muyter kfree(pvd); 2896ceea22bSPhilippe De Muyter } 2906ceea22bSPhilippe De Muyter kfree(n); 2916ceea22bSPhilippe De Muyter kfree(lvip); 2926ceea22bSPhilippe De Muyter return ret; 2936ceea22bSPhilippe De Muyter } 294