1*6ceea22bSPhilippe De Muyter /* 2*6ceea22bSPhilippe De Muyter * fs/partitions/aix.c 3*6ceea22bSPhilippe De Muyter * 4*6ceea22bSPhilippe De Muyter * Copyright (C) 2012-2013 Philippe De Muyter <phdm@macqel.be> 5*6ceea22bSPhilippe De Muyter */ 6*6ceea22bSPhilippe De Muyter 7*6ceea22bSPhilippe De Muyter #include "check.h" 8*6ceea22bSPhilippe De Muyter #include "aix.h" 9*6ceea22bSPhilippe De Muyter 10*6ceea22bSPhilippe De Muyter struct lvm_rec { 11*6ceea22bSPhilippe De Muyter char lvm_id[4]; /* "_LVM" */ 12*6ceea22bSPhilippe De Muyter char reserved4[16]; 13*6ceea22bSPhilippe De Muyter __be32 lvmarea_len; 14*6ceea22bSPhilippe De Muyter __be32 vgda_len; 15*6ceea22bSPhilippe De Muyter __be32 vgda_psn[2]; 16*6ceea22bSPhilippe De Muyter char reserved36[10]; 17*6ceea22bSPhilippe De Muyter __be16 pp_size; /* log2(pp_size) */ 18*6ceea22bSPhilippe De Muyter char reserved46[12]; 19*6ceea22bSPhilippe De Muyter __be16 version; 20*6ceea22bSPhilippe De Muyter }; 21*6ceea22bSPhilippe De Muyter 22*6ceea22bSPhilippe De Muyter struct vgda { 23*6ceea22bSPhilippe De Muyter __be32 secs; 24*6ceea22bSPhilippe De Muyter __be32 usec; 25*6ceea22bSPhilippe De Muyter char reserved8[16]; 26*6ceea22bSPhilippe De Muyter __be16 numlvs; 27*6ceea22bSPhilippe De Muyter __be16 maxlvs; 28*6ceea22bSPhilippe De Muyter __be16 pp_size; 29*6ceea22bSPhilippe De Muyter __be16 numpvs; 30*6ceea22bSPhilippe De Muyter __be16 total_vgdas; 31*6ceea22bSPhilippe De Muyter __be16 vgda_size; 32*6ceea22bSPhilippe De Muyter }; 33*6ceea22bSPhilippe De Muyter 34*6ceea22bSPhilippe De Muyter struct lvd { 35*6ceea22bSPhilippe De Muyter __be16 lv_ix; 36*6ceea22bSPhilippe De Muyter __be16 res2; 37*6ceea22bSPhilippe De Muyter __be16 res4; 38*6ceea22bSPhilippe De Muyter __be16 maxsize; 39*6ceea22bSPhilippe De Muyter __be16 lv_state; 40*6ceea22bSPhilippe De Muyter __be16 mirror; 41*6ceea22bSPhilippe De Muyter __be16 mirror_policy; 42*6ceea22bSPhilippe De Muyter __be16 num_lps; 43*6ceea22bSPhilippe De Muyter __be16 res10[8]; 44*6ceea22bSPhilippe De Muyter }; 45*6ceea22bSPhilippe De Muyter 46*6ceea22bSPhilippe De Muyter struct lvname { 47*6ceea22bSPhilippe De Muyter char name[64]; 48*6ceea22bSPhilippe De Muyter }; 49*6ceea22bSPhilippe De Muyter 50*6ceea22bSPhilippe De Muyter struct ppe { 51*6ceea22bSPhilippe De Muyter __be16 lv_ix; 52*6ceea22bSPhilippe De Muyter unsigned short res2; 53*6ceea22bSPhilippe De Muyter unsigned short res4; 54*6ceea22bSPhilippe De Muyter __be16 lp_ix; 55*6ceea22bSPhilippe De Muyter unsigned short res8[12]; 56*6ceea22bSPhilippe De Muyter }; 57*6ceea22bSPhilippe De Muyter 58*6ceea22bSPhilippe De Muyter struct pvd { 59*6ceea22bSPhilippe De Muyter char reserved0[16]; 60*6ceea22bSPhilippe De Muyter __be16 pp_count; 61*6ceea22bSPhilippe De Muyter char reserved18[2]; 62*6ceea22bSPhilippe De Muyter __be32 psn_part1; 63*6ceea22bSPhilippe De Muyter char reserved24[8]; 64*6ceea22bSPhilippe De Muyter struct ppe ppe[1016]; 65*6ceea22bSPhilippe De Muyter }; 66*6ceea22bSPhilippe De Muyter 67*6ceea22bSPhilippe De Muyter #define LVM_MAXLVS 256 68*6ceea22bSPhilippe De Muyter 69*6ceea22bSPhilippe De Muyter /** 70*6ceea22bSPhilippe De Muyter * last_lba(): return number of last logical block of device 71*6ceea22bSPhilippe De Muyter * @bdev: block device 72*6ceea22bSPhilippe De Muyter * 73*6ceea22bSPhilippe De Muyter * Description: Returns last LBA value on success, 0 on error. 74*6ceea22bSPhilippe De Muyter * This is stored (by sd and ide-geometry) in 75*6ceea22bSPhilippe De Muyter * the part[0] entry for this disk, and is the number of 76*6ceea22bSPhilippe De Muyter * physical sectors available on the disk. 77*6ceea22bSPhilippe De Muyter */ 78*6ceea22bSPhilippe De Muyter static u64 last_lba(struct block_device *bdev) 79*6ceea22bSPhilippe De Muyter { 80*6ceea22bSPhilippe De Muyter if (!bdev || !bdev->bd_inode) 81*6ceea22bSPhilippe De Muyter return 0; 82*6ceea22bSPhilippe De Muyter return (bdev->bd_inode->i_size >> 9) - 1ULL; 83*6ceea22bSPhilippe De Muyter } 84*6ceea22bSPhilippe De Muyter 85*6ceea22bSPhilippe De Muyter /** 86*6ceea22bSPhilippe De Muyter * read_lba(): Read bytes from disk, starting at given LBA 87*6ceea22bSPhilippe De Muyter * @state 88*6ceea22bSPhilippe De Muyter * @lba 89*6ceea22bSPhilippe De Muyter * @buffer 90*6ceea22bSPhilippe De Muyter * @count 91*6ceea22bSPhilippe De Muyter * 92*6ceea22bSPhilippe De Muyter * Description: Reads @count bytes from @state->bdev into @buffer. 93*6ceea22bSPhilippe De Muyter * Returns number of bytes read on success, 0 on error. 94*6ceea22bSPhilippe De Muyter */ 95*6ceea22bSPhilippe De Muyter static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer, 96*6ceea22bSPhilippe De Muyter size_t count) 97*6ceea22bSPhilippe De Muyter { 98*6ceea22bSPhilippe De Muyter size_t totalreadcount = 0; 99*6ceea22bSPhilippe De Muyter 100*6ceea22bSPhilippe De Muyter if (!buffer || lba + count / 512 > last_lba(state->bdev)) 101*6ceea22bSPhilippe De Muyter return 0; 102*6ceea22bSPhilippe De Muyter 103*6ceea22bSPhilippe De Muyter while (count) { 104*6ceea22bSPhilippe De Muyter int copied = 512; 105*6ceea22bSPhilippe De Muyter Sector sect; 106*6ceea22bSPhilippe De Muyter unsigned char *data = read_part_sector(state, lba++, §); 107*6ceea22bSPhilippe De Muyter if (!data) 108*6ceea22bSPhilippe De Muyter break; 109*6ceea22bSPhilippe De Muyter if (copied > count) 110*6ceea22bSPhilippe De Muyter copied = count; 111*6ceea22bSPhilippe De Muyter memcpy(buffer, data, copied); 112*6ceea22bSPhilippe De Muyter put_dev_sector(sect); 113*6ceea22bSPhilippe De Muyter buffer += copied; 114*6ceea22bSPhilippe De Muyter totalreadcount += copied; 115*6ceea22bSPhilippe De Muyter count -= copied; 116*6ceea22bSPhilippe De Muyter } 117*6ceea22bSPhilippe De Muyter return totalreadcount; 118*6ceea22bSPhilippe De Muyter } 119*6ceea22bSPhilippe De Muyter 120*6ceea22bSPhilippe De Muyter /** 121*6ceea22bSPhilippe De Muyter * alloc_pvd(): reads physical volume descriptor 122*6ceea22bSPhilippe De Muyter * @state 123*6ceea22bSPhilippe De Muyter * @lba 124*6ceea22bSPhilippe De Muyter * 125*6ceea22bSPhilippe De Muyter * Description: Returns pvd on success, NULL on error. 126*6ceea22bSPhilippe De Muyter * Allocates space for pvd and fill it with disk blocks at @lba 127*6ceea22bSPhilippe De Muyter * Notes: remember to free pvd when you're done! 128*6ceea22bSPhilippe De Muyter */ 129*6ceea22bSPhilippe De Muyter static struct pvd *alloc_pvd(struct parsed_partitions *state, u32 lba) 130*6ceea22bSPhilippe De Muyter { 131*6ceea22bSPhilippe De Muyter size_t count = sizeof(struct pvd); 132*6ceea22bSPhilippe De Muyter struct pvd *p; 133*6ceea22bSPhilippe De Muyter 134*6ceea22bSPhilippe De Muyter p = kmalloc(count, GFP_KERNEL); 135*6ceea22bSPhilippe De Muyter if (!p) 136*6ceea22bSPhilippe De Muyter return NULL; 137*6ceea22bSPhilippe De Muyter 138*6ceea22bSPhilippe De Muyter if (read_lba(state, lba, (u8 *) p, count) < count) { 139*6ceea22bSPhilippe De Muyter kfree(p); 140*6ceea22bSPhilippe De Muyter return NULL; 141*6ceea22bSPhilippe De Muyter } 142*6ceea22bSPhilippe De Muyter return p; 143*6ceea22bSPhilippe De Muyter } 144*6ceea22bSPhilippe De Muyter 145*6ceea22bSPhilippe De Muyter /** 146*6ceea22bSPhilippe De Muyter * alloc_lvn(): reads logical volume names 147*6ceea22bSPhilippe De Muyter * @state 148*6ceea22bSPhilippe De Muyter * @lba 149*6ceea22bSPhilippe De Muyter * 150*6ceea22bSPhilippe De Muyter * Description: Returns lvn on success, NULL on error. 151*6ceea22bSPhilippe De Muyter * Allocates space for lvn and fill it with disk blocks at @lba 152*6ceea22bSPhilippe De Muyter * Notes: remember to free lvn when you're done! 153*6ceea22bSPhilippe De Muyter */ 154*6ceea22bSPhilippe De Muyter static struct lvname *alloc_lvn(struct parsed_partitions *state, u32 lba) 155*6ceea22bSPhilippe De Muyter { 156*6ceea22bSPhilippe De Muyter size_t count = sizeof(struct lvname) * LVM_MAXLVS; 157*6ceea22bSPhilippe De Muyter struct lvname *p; 158*6ceea22bSPhilippe De Muyter 159*6ceea22bSPhilippe De Muyter p = kmalloc(count, GFP_KERNEL); 160*6ceea22bSPhilippe De Muyter if (!p) 161*6ceea22bSPhilippe De Muyter return NULL; 162*6ceea22bSPhilippe De Muyter 163*6ceea22bSPhilippe De Muyter if (read_lba(state, lba, (u8 *) p, count) < count) { 164*6ceea22bSPhilippe De Muyter kfree(p); 165*6ceea22bSPhilippe De Muyter return NULL; 166*6ceea22bSPhilippe De Muyter } 167*6ceea22bSPhilippe De Muyter return p; 168*6ceea22bSPhilippe De Muyter } 169*6ceea22bSPhilippe De Muyter 170*6ceea22bSPhilippe De Muyter int aix_partition(struct parsed_partitions *state) 171*6ceea22bSPhilippe De Muyter { 172*6ceea22bSPhilippe De Muyter int ret = 0; 173*6ceea22bSPhilippe De Muyter Sector sect; 174*6ceea22bSPhilippe De Muyter unsigned char *d; 175*6ceea22bSPhilippe De Muyter u32 pp_bytes_size; 176*6ceea22bSPhilippe De Muyter u32 pp_blocks_size = 0; 177*6ceea22bSPhilippe De Muyter u32 vgda_sector = 0; 178*6ceea22bSPhilippe De Muyter u32 vgda_len = 0; 179*6ceea22bSPhilippe De Muyter int numlvs = 0; 180*6ceea22bSPhilippe De Muyter struct pvd *pvd; 181*6ceea22bSPhilippe De Muyter struct lv_info { 182*6ceea22bSPhilippe De Muyter unsigned short pps_per_lv; 183*6ceea22bSPhilippe De Muyter unsigned short pps_found; 184*6ceea22bSPhilippe De Muyter unsigned char lv_is_contiguous; 185*6ceea22bSPhilippe De Muyter } *lvip; 186*6ceea22bSPhilippe De Muyter struct lvname *n = NULL; 187*6ceea22bSPhilippe De Muyter 188*6ceea22bSPhilippe De Muyter d = read_part_sector(state, 7, §); 189*6ceea22bSPhilippe De Muyter if (d) { 190*6ceea22bSPhilippe De Muyter struct lvm_rec *p = (struct lvm_rec *)d; 191*6ceea22bSPhilippe De Muyter u16 lvm_version = be16_to_cpu(p->version); 192*6ceea22bSPhilippe De Muyter char tmp[64]; 193*6ceea22bSPhilippe De Muyter 194*6ceea22bSPhilippe De Muyter if (lvm_version == 1) { 195*6ceea22bSPhilippe De Muyter int pp_size_log2 = be16_to_cpu(p->pp_size); 196*6ceea22bSPhilippe De Muyter 197*6ceea22bSPhilippe De Muyter pp_bytes_size = 1 << pp_size_log2; 198*6ceea22bSPhilippe De Muyter pp_blocks_size = pp_bytes_size / 512; 199*6ceea22bSPhilippe De Muyter snprintf(tmp, sizeof(tmp), 200*6ceea22bSPhilippe De Muyter " AIX LVM header version %u found\n", 201*6ceea22bSPhilippe De Muyter lvm_version); 202*6ceea22bSPhilippe De Muyter vgda_len = be32_to_cpu(p->vgda_len); 203*6ceea22bSPhilippe De Muyter vgda_sector = be32_to_cpu(p->vgda_psn[0]); 204*6ceea22bSPhilippe De Muyter } else { 205*6ceea22bSPhilippe De Muyter snprintf(tmp, sizeof(tmp), 206*6ceea22bSPhilippe De Muyter " unsupported AIX LVM version %d found\n", 207*6ceea22bSPhilippe De Muyter lvm_version); 208*6ceea22bSPhilippe De Muyter } 209*6ceea22bSPhilippe De Muyter strlcat(state->pp_buf, tmp, PAGE_SIZE); 210*6ceea22bSPhilippe De Muyter put_dev_sector(sect); 211*6ceea22bSPhilippe De Muyter } 212*6ceea22bSPhilippe De Muyter if (vgda_sector && (d = read_part_sector(state, vgda_sector, §))) { 213*6ceea22bSPhilippe De Muyter struct vgda *p = (struct vgda *)d; 214*6ceea22bSPhilippe De Muyter 215*6ceea22bSPhilippe De Muyter numlvs = be16_to_cpu(p->numlvs); 216*6ceea22bSPhilippe De Muyter put_dev_sector(sect); 217*6ceea22bSPhilippe De Muyter } 218*6ceea22bSPhilippe De Muyter lvip = kzalloc(sizeof(struct lv_info) * state->limit, GFP_KERNEL); 219*6ceea22bSPhilippe De Muyter if (!lvip) 220*6ceea22bSPhilippe De Muyter return 0; 221*6ceea22bSPhilippe De Muyter if (numlvs && (d = read_part_sector(state, vgda_sector + 1, §))) { 222*6ceea22bSPhilippe De Muyter struct lvd *p = (struct lvd *)d; 223*6ceea22bSPhilippe De Muyter int i; 224*6ceea22bSPhilippe De Muyter 225*6ceea22bSPhilippe De Muyter n = alloc_lvn(state, vgda_sector + vgda_len - 33); 226*6ceea22bSPhilippe De Muyter if (n) { 227*6ceea22bSPhilippe De Muyter int foundlvs = 0; 228*6ceea22bSPhilippe De Muyter 229*6ceea22bSPhilippe De Muyter for (i = 0; foundlvs < numlvs && i < state->limit; i += 1) { 230*6ceea22bSPhilippe De Muyter lvip[i].pps_per_lv = be16_to_cpu(p[i].num_lps); 231*6ceea22bSPhilippe De Muyter if (lvip[i].pps_per_lv) 232*6ceea22bSPhilippe De Muyter foundlvs += 1; 233*6ceea22bSPhilippe De Muyter } 234*6ceea22bSPhilippe De Muyter } 235*6ceea22bSPhilippe De Muyter put_dev_sector(sect); 236*6ceea22bSPhilippe De Muyter } 237*6ceea22bSPhilippe De Muyter pvd = alloc_pvd(state, vgda_sector + 17); 238*6ceea22bSPhilippe De Muyter if (pvd) { 239*6ceea22bSPhilippe De Muyter int numpps = be16_to_cpu(pvd->pp_count); 240*6ceea22bSPhilippe De Muyter int psn_part1 = be32_to_cpu(pvd->psn_part1); 241*6ceea22bSPhilippe De Muyter int i; 242*6ceea22bSPhilippe De Muyter int cur_lv_ix = -1; 243*6ceea22bSPhilippe De Muyter int next_lp_ix = 1; 244*6ceea22bSPhilippe De Muyter int lp_ix; 245*6ceea22bSPhilippe De Muyter 246*6ceea22bSPhilippe De Muyter for (i = 0; i < numpps; i += 1) { 247*6ceea22bSPhilippe De Muyter struct ppe *p = pvd->ppe + i; 248*6ceea22bSPhilippe De Muyter unsigned int lv_ix; 249*6ceea22bSPhilippe De Muyter 250*6ceea22bSPhilippe De Muyter lp_ix = be16_to_cpu(p->lp_ix); 251*6ceea22bSPhilippe De Muyter if (!lp_ix) { 252*6ceea22bSPhilippe De Muyter next_lp_ix = 1; 253*6ceea22bSPhilippe De Muyter continue; 254*6ceea22bSPhilippe De Muyter } 255*6ceea22bSPhilippe De Muyter lv_ix = be16_to_cpu(p->lv_ix) - 1; 256*6ceea22bSPhilippe De Muyter if (lv_ix > state->limit) { 257*6ceea22bSPhilippe De Muyter cur_lv_ix = -1; 258*6ceea22bSPhilippe De Muyter continue; 259*6ceea22bSPhilippe De Muyter } 260*6ceea22bSPhilippe De Muyter lvip[lv_ix].pps_found += 1; 261*6ceea22bSPhilippe De Muyter if (lp_ix == 1) { 262*6ceea22bSPhilippe De Muyter cur_lv_ix = lv_ix; 263*6ceea22bSPhilippe De Muyter next_lp_ix = 1; 264*6ceea22bSPhilippe De Muyter } else if (lv_ix != cur_lv_ix || lp_ix != next_lp_ix) { 265*6ceea22bSPhilippe De Muyter next_lp_ix = 1; 266*6ceea22bSPhilippe De Muyter continue; 267*6ceea22bSPhilippe De Muyter } 268*6ceea22bSPhilippe De Muyter if (lp_ix == lvip[lv_ix].pps_per_lv) { 269*6ceea22bSPhilippe De Muyter char tmp[70]; 270*6ceea22bSPhilippe De Muyter 271*6ceea22bSPhilippe De Muyter put_partition(state, lv_ix + 1, 272*6ceea22bSPhilippe De Muyter (i + 1 - lp_ix) * pp_blocks_size + psn_part1, 273*6ceea22bSPhilippe De Muyter lvip[lv_ix].pps_per_lv * pp_blocks_size); 274*6ceea22bSPhilippe De Muyter snprintf(tmp, sizeof(tmp), " <%s>\n", 275*6ceea22bSPhilippe De Muyter n[lv_ix].name); 276*6ceea22bSPhilippe De Muyter strlcat(state->pp_buf, tmp, PAGE_SIZE); 277*6ceea22bSPhilippe De Muyter lvip[lv_ix].lv_is_contiguous = 1; 278*6ceea22bSPhilippe De Muyter ret = 1; 279*6ceea22bSPhilippe De Muyter next_lp_ix = 1; 280*6ceea22bSPhilippe De Muyter } else 281*6ceea22bSPhilippe De Muyter next_lp_ix += 1; 282*6ceea22bSPhilippe De Muyter } 283*6ceea22bSPhilippe De Muyter for (i = 0; i < state->limit; i += 1) 284*6ceea22bSPhilippe De Muyter if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) 285*6ceea22bSPhilippe De Muyter pr_warn("partition %s (%u pp's found) is " 286*6ceea22bSPhilippe De Muyter "not contiguous\n", 287*6ceea22bSPhilippe De Muyter n[i].name, lvip[i].pps_found); 288*6ceea22bSPhilippe De Muyter kfree(pvd); 289*6ceea22bSPhilippe De Muyter } 290*6ceea22bSPhilippe De Muyter kfree(n); 291*6ceea22bSPhilippe De Muyter kfree(lvip); 292*6ceea22bSPhilippe De Muyter return ret; 293*6ceea22bSPhilippe De Muyter } 294