1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 26ceea22bSPhilippe De Muyter /* 36ceea22bSPhilippe De Muyter * fs/partitions/aix.c 46ceea22bSPhilippe De Muyter * 56ceea22bSPhilippe De Muyter * Copyright (C) 2012-2013 Philippe De Muyter <phdm@macqel.be> 66ceea22bSPhilippe De Muyter */ 76ceea22bSPhilippe De Muyter 86ceea22bSPhilippe De Muyter #include "check.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 * read_lba(): Read bytes from disk, starting at given LBA 716ceea22bSPhilippe De Muyter * @state 726ceea22bSPhilippe De Muyter * @lba 736ceea22bSPhilippe De Muyter * @buffer 746ceea22bSPhilippe De Muyter * @count 756ceea22bSPhilippe De Muyter * 76*a08aa9bcSChristoph Hellwig * Description: Reads @count bytes from @state->disk into @buffer. 776ceea22bSPhilippe De Muyter * Returns number of bytes read on success, 0 on error. 786ceea22bSPhilippe De Muyter */ 796ceea22bSPhilippe De Muyter static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer, 806ceea22bSPhilippe De Muyter size_t count) 816ceea22bSPhilippe De Muyter { 826ceea22bSPhilippe De Muyter size_t totalreadcount = 0; 836ceea22bSPhilippe De Muyter 84*a08aa9bcSChristoph Hellwig if (!buffer || lba + count / 512 > get_capacity(state->disk) - 1ULL) 856ceea22bSPhilippe De Muyter return 0; 866ceea22bSPhilippe De Muyter 876ceea22bSPhilippe De Muyter while (count) { 886ceea22bSPhilippe De Muyter int copied = 512; 896ceea22bSPhilippe De Muyter Sector sect; 906ceea22bSPhilippe De Muyter unsigned char *data = read_part_sector(state, lba++, §); 916ceea22bSPhilippe De Muyter if (!data) 926ceea22bSPhilippe De Muyter break; 936ceea22bSPhilippe De Muyter if (copied > count) 946ceea22bSPhilippe De Muyter copied = count; 956ceea22bSPhilippe De Muyter memcpy(buffer, data, copied); 966ceea22bSPhilippe De Muyter put_dev_sector(sect); 976ceea22bSPhilippe De Muyter buffer += copied; 986ceea22bSPhilippe De Muyter totalreadcount += copied; 996ceea22bSPhilippe De Muyter count -= copied; 1006ceea22bSPhilippe De Muyter } 1016ceea22bSPhilippe De Muyter return totalreadcount; 1026ceea22bSPhilippe De Muyter } 1036ceea22bSPhilippe De Muyter 1046ceea22bSPhilippe De Muyter /** 1056ceea22bSPhilippe De Muyter * alloc_pvd(): reads physical volume descriptor 1066ceea22bSPhilippe De Muyter * @state 1076ceea22bSPhilippe De Muyter * @lba 1086ceea22bSPhilippe De Muyter * 1096ceea22bSPhilippe De Muyter * Description: Returns pvd on success, NULL on error. 1106ceea22bSPhilippe De Muyter * Allocates space for pvd and fill it with disk blocks at @lba 1116ceea22bSPhilippe De Muyter * Notes: remember to free pvd when you're done! 1126ceea22bSPhilippe De Muyter */ 1136ceea22bSPhilippe De Muyter static struct pvd *alloc_pvd(struct parsed_partitions *state, u32 lba) 1146ceea22bSPhilippe De Muyter { 1156ceea22bSPhilippe De Muyter size_t count = sizeof(struct pvd); 1166ceea22bSPhilippe De Muyter struct pvd *p; 1176ceea22bSPhilippe De Muyter 1186ceea22bSPhilippe De Muyter p = kmalloc(count, GFP_KERNEL); 1196ceea22bSPhilippe De Muyter if (!p) 1206ceea22bSPhilippe De Muyter return NULL; 1216ceea22bSPhilippe De Muyter 1226ceea22bSPhilippe De Muyter if (read_lba(state, lba, (u8 *) p, count) < count) { 1236ceea22bSPhilippe De Muyter kfree(p); 1246ceea22bSPhilippe De Muyter return NULL; 1256ceea22bSPhilippe De Muyter } 1266ceea22bSPhilippe De Muyter return p; 1276ceea22bSPhilippe De Muyter } 1286ceea22bSPhilippe De Muyter 1296ceea22bSPhilippe De Muyter /** 1306ceea22bSPhilippe De Muyter * alloc_lvn(): reads logical volume names 1316ceea22bSPhilippe De Muyter * @state 1326ceea22bSPhilippe De Muyter * @lba 1336ceea22bSPhilippe De Muyter * 1346ceea22bSPhilippe De Muyter * Description: Returns lvn on success, NULL on error. 1356ceea22bSPhilippe De Muyter * Allocates space for lvn and fill it with disk blocks at @lba 1366ceea22bSPhilippe De Muyter * Notes: remember to free lvn when you're done! 1376ceea22bSPhilippe De Muyter */ 1386ceea22bSPhilippe De Muyter static struct lvname *alloc_lvn(struct parsed_partitions *state, u32 lba) 1396ceea22bSPhilippe De Muyter { 1406ceea22bSPhilippe De Muyter size_t count = sizeof(struct lvname) * LVM_MAXLVS; 1416ceea22bSPhilippe De Muyter struct lvname *p; 1426ceea22bSPhilippe De Muyter 1436ceea22bSPhilippe De Muyter p = kmalloc(count, GFP_KERNEL); 1446ceea22bSPhilippe De Muyter if (!p) 1456ceea22bSPhilippe De Muyter return NULL; 1466ceea22bSPhilippe De Muyter 1476ceea22bSPhilippe De Muyter if (read_lba(state, lba, (u8 *) p, count) < count) { 1486ceea22bSPhilippe De Muyter kfree(p); 1496ceea22bSPhilippe De Muyter return NULL; 1506ceea22bSPhilippe De Muyter } 1516ceea22bSPhilippe De Muyter return p; 1526ceea22bSPhilippe De Muyter } 1536ceea22bSPhilippe De Muyter 1546ceea22bSPhilippe De Muyter int aix_partition(struct parsed_partitions *state) 1556ceea22bSPhilippe De Muyter { 1566ceea22bSPhilippe De Muyter int ret = 0; 1576ceea22bSPhilippe De Muyter Sector sect; 1586ceea22bSPhilippe De Muyter unsigned char *d; 1596ceea22bSPhilippe De Muyter u32 pp_bytes_size; 1606ceea22bSPhilippe De Muyter u32 pp_blocks_size = 0; 1616ceea22bSPhilippe De Muyter u32 vgda_sector = 0; 1626ceea22bSPhilippe De Muyter u32 vgda_len = 0; 1636ceea22bSPhilippe De Muyter int numlvs = 0; 16414cb2c8aSMauricio Faria de Oliveira struct pvd *pvd = NULL; 1656ceea22bSPhilippe De Muyter struct lv_info { 1666ceea22bSPhilippe De Muyter unsigned short pps_per_lv; 1676ceea22bSPhilippe De Muyter unsigned short pps_found; 1686ceea22bSPhilippe De Muyter unsigned char lv_is_contiguous; 1696ceea22bSPhilippe De Muyter } *lvip; 1706ceea22bSPhilippe De Muyter struct lvname *n = NULL; 1716ceea22bSPhilippe De Muyter 1726ceea22bSPhilippe De Muyter d = read_part_sector(state, 7, §); 1736ceea22bSPhilippe De Muyter if (d) { 1746ceea22bSPhilippe De Muyter struct lvm_rec *p = (struct lvm_rec *)d; 1756ceea22bSPhilippe De Muyter u16 lvm_version = be16_to_cpu(p->version); 1766ceea22bSPhilippe De Muyter char tmp[64]; 1776ceea22bSPhilippe De Muyter 1786ceea22bSPhilippe De Muyter if (lvm_version == 1) { 1796ceea22bSPhilippe De Muyter int pp_size_log2 = be16_to_cpu(p->pp_size); 1806ceea22bSPhilippe De Muyter 1816ceea22bSPhilippe De Muyter pp_bytes_size = 1 << pp_size_log2; 1826ceea22bSPhilippe De Muyter pp_blocks_size = pp_bytes_size / 512; 1836ceea22bSPhilippe De Muyter snprintf(tmp, sizeof(tmp), 1846ceea22bSPhilippe De Muyter " AIX LVM header version %u found\n", 1856ceea22bSPhilippe De Muyter lvm_version); 1866ceea22bSPhilippe De Muyter vgda_len = be32_to_cpu(p->vgda_len); 1876ceea22bSPhilippe De Muyter vgda_sector = be32_to_cpu(p->vgda_psn[0]); 1886ceea22bSPhilippe De Muyter } else { 1896ceea22bSPhilippe De Muyter snprintf(tmp, sizeof(tmp), 1906ceea22bSPhilippe De Muyter " unsupported AIX LVM version %d found\n", 1916ceea22bSPhilippe De Muyter lvm_version); 1926ceea22bSPhilippe De Muyter } 1936ceea22bSPhilippe De Muyter strlcat(state->pp_buf, tmp, PAGE_SIZE); 1946ceea22bSPhilippe De Muyter put_dev_sector(sect); 1956ceea22bSPhilippe De Muyter } 1966ceea22bSPhilippe De Muyter if (vgda_sector && (d = read_part_sector(state, vgda_sector, §))) { 1976ceea22bSPhilippe De Muyter struct vgda *p = (struct vgda *)d; 1986ceea22bSPhilippe De Muyter 1996ceea22bSPhilippe De Muyter numlvs = be16_to_cpu(p->numlvs); 2006ceea22bSPhilippe De Muyter put_dev_sector(sect); 2016ceea22bSPhilippe De Muyter } 202472d5e2aSFabian Frederick lvip = kcalloc(state->limit, sizeof(struct lv_info), GFP_KERNEL); 2036ceea22bSPhilippe De Muyter if (!lvip) 2046ceea22bSPhilippe De Muyter return 0; 2056ceea22bSPhilippe De Muyter if (numlvs && (d = read_part_sector(state, vgda_sector + 1, §))) { 2066ceea22bSPhilippe De Muyter struct lvd *p = (struct lvd *)d; 2076ceea22bSPhilippe De Muyter int i; 2086ceea22bSPhilippe De Muyter 2096ceea22bSPhilippe De Muyter n = alloc_lvn(state, vgda_sector + vgda_len - 33); 2106ceea22bSPhilippe De Muyter if (n) { 2116ceea22bSPhilippe De Muyter int foundlvs = 0; 2126ceea22bSPhilippe De Muyter 2136ceea22bSPhilippe De Muyter for (i = 0; foundlvs < numlvs && i < state->limit; i += 1) { 2146ceea22bSPhilippe De Muyter lvip[i].pps_per_lv = be16_to_cpu(p[i].num_lps); 2156ceea22bSPhilippe De Muyter if (lvip[i].pps_per_lv) 2166ceea22bSPhilippe De Muyter foundlvs += 1; 2176ceea22bSPhilippe De Muyter } 21814cb2c8aSMauricio Faria de Oliveira /* pvd loops depend on n[].name and lvip[].pps_per_lv */ 21914cb2c8aSMauricio Faria de Oliveira pvd = alloc_pvd(state, vgda_sector + 17); 2206ceea22bSPhilippe De Muyter } 2216ceea22bSPhilippe De Muyter put_dev_sector(sect); 2226ceea22bSPhilippe De Muyter } 2236ceea22bSPhilippe De Muyter if (pvd) { 2246ceea22bSPhilippe De Muyter int numpps = be16_to_cpu(pvd->pp_count); 2256ceea22bSPhilippe De Muyter int psn_part1 = be32_to_cpu(pvd->psn_part1); 2266ceea22bSPhilippe De Muyter int i; 2276ceea22bSPhilippe De Muyter int cur_lv_ix = -1; 2286ceea22bSPhilippe De Muyter int next_lp_ix = 1; 2296ceea22bSPhilippe De Muyter int lp_ix; 2306ceea22bSPhilippe De Muyter 2316ceea22bSPhilippe De Muyter for (i = 0; i < numpps; i += 1) { 2326ceea22bSPhilippe De Muyter struct ppe *p = pvd->ppe + i; 2336ceea22bSPhilippe De Muyter unsigned int lv_ix; 2346ceea22bSPhilippe De Muyter 2356ceea22bSPhilippe De Muyter lp_ix = be16_to_cpu(p->lp_ix); 2366ceea22bSPhilippe De Muyter if (!lp_ix) { 2376ceea22bSPhilippe De Muyter next_lp_ix = 1; 2386ceea22bSPhilippe De Muyter continue; 2396ceea22bSPhilippe De Muyter } 2406ceea22bSPhilippe De Muyter lv_ix = be16_to_cpu(p->lv_ix) - 1; 241d97a86c1SDan Carpenter if (lv_ix >= state->limit) { 2426ceea22bSPhilippe De Muyter cur_lv_ix = -1; 2436ceea22bSPhilippe De Muyter continue; 2446ceea22bSPhilippe De Muyter } 2456ceea22bSPhilippe De Muyter lvip[lv_ix].pps_found += 1; 2466ceea22bSPhilippe De Muyter if (lp_ix == 1) { 2476ceea22bSPhilippe De Muyter cur_lv_ix = lv_ix; 2486ceea22bSPhilippe De Muyter next_lp_ix = 1; 2496ceea22bSPhilippe De Muyter } else if (lv_ix != cur_lv_ix || lp_ix != next_lp_ix) { 2506ceea22bSPhilippe De Muyter next_lp_ix = 1; 2516ceea22bSPhilippe De Muyter continue; 2526ceea22bSPhilippe De Muyter } 2536ceea22bSPhilippe De Muyter if (lp_ix == lvip[lv_ix].pps_per_lv) { 2546ceea22bSPhilippe De Muyter char tmp[70]; 2556ceea22bSPhilippe De Muyter 2566ceea22bSPhilippe De Muyter put_partition(state, lv_ix + 1, 2576ceea22bSPhilippe De Muyter (i + 1 - lp_ix) * pp_blocks_size + psn_part1, 2586ceea22bSPhilippe De Muyter lvip[lv_ix].pps_per_lv * pp_blocks_size); 2596ceea22bSPhilippe De Muyter snprintf(tmp, sizeof(tmp), " <%s>\n", 2606ceea22bSPhilippe De Muyter n[lv_ix].name); 2616ceea22bSPhilippe De Muyter strlcat(state->pp_buf, tmp, PAGE_SIZE); 2626ceea22bSPhilippe De Muyter lvip[lv_ix].lv_is_contiguous = 1; 2636ceea22bSPhilippe De Muyter ret = 1; 2646ceea22bSPhilippe De Muyter next_lp_ix = 1; 2656ceea22bSPhilippe De Muyter } else 2666ceea22bSPhilippe De Muyter next_lp_ix += 1; 2676ceea22bSPhilippe De Muyter } 2686ceea22bSPhilippe De Muyter for (i = 0; i < state->limit; i += 1) 269d43fdae7SMauricio Faria de Oliveira if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) { 270d43fdae7SMauricio Faria de Oliveira char tmp[sizeof(n[i].name) + 1]; // null char 271d43fdae7SMauricio Faria de Oliveira 272d43fdae7SMauricio Faria de Oliveira snprintf(tmp, sizeof(tmp), "%s", n[i].name); 2736ceea22bSPhilippe De Muyter pr_warn("partition %s (%u pp's found) is " 2746ceea22bSPhilippe De Muyter "not contiguous\n", 275d43fdae7SMauricio Faria de Oliveira tmp, lvip[i].pps_found); 276d43fdae7SMauricio Faria de Oliveira } 2776ceea22bSPhilippe De Muyter kfree(pvd); 2786ceea22bSPhilippe De Muyter } 2796ceea22bSPhilippe De Muyter kfree(n); 2806ceea22bSPhilippe De Muyter kfree(lvip); 2816ceea22bSPhilippe De Muyter return ret; 2826ceea22bSPhilippe De Muyter } 283