1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2012-2013 Philippe De Muyter <phdm@macqel.be>
11 char lvm_id
[4]; /* "_LVM" */
17 __be16 pp_size
; /* log2(pp_size) */
55 unsigned short res8
[12];
67 #define LVM_MAXLVS 256
70 * last_lba(): return number of last logical block of device
73 * Description: Returns last LBA value on success, 0 on error.
74 * This is stored (by sd and ide-geometry) in
75 * the part[0] entry for this disk, and is the number of
76 * physical sectors available on the disk.
78 static u64
last_lba(struct block_device
*bdev
)
80 if (!bdev
|| !bdev
->bd_inode
)
82 return (bdev
->bd_inode
->i_size
>> 9) - 1ULL;
86 * read_lba(): Read bytes from disk, starting at given LBA
92 * Description: Reads @count bytes from @state->bdev into @buffer.
93 * Returns number of bytes read on success, 0 on error.
95 static size_t read_lba(struct parsed_partitions
*state
, u64 lba
, u8
*buffer
,
98 size_t totalreadcount
= 0;
100 if (!buffer
|| lba
+ count
/ 512 > last_lba(state
->bdev
))
106 unsigned char *data
= read_part_sector(state
, lba
++, §
);
111 memcpy(buffer
, data
, copied
);
112 put_dev_sector(sect
);
114 totalreadcount
+= copied
;
117 return totalreadcount
;
121 * alloc_pvd(): reads physical volume descriptor
125 * Description: Returns pvd on success, NULL on error.
126 * Allocates space for pvd and fill it with disk blocks at @lba
127 * Notes: remember to free pvd when you're done!
129 static struct pvd
*alloc_pvd(struct parsed_partitions
*state
, u32 lba
)
131 size_t count
= sizeof(struct pvd
);
134 p
= kmalloc(count
, GFP_KERNEL
);
138 if (read_lba(state
, lba
, (u8
*) p
, count
) < count
) {
146 * alloc_lvn(): reads logical volume names
150 * Description: Returns lvn on success, NULL on error.
151 * Allocates space for lvn and fill it with disk blocks at @lba
152 * Notes: remember to free lvn when you're done!
154 static struct lvname
*alloc_lvn(struct parsed_partitions
*state
, u32 lba
)
156 size_t count
= sizeof(struct lvname
) * LVM_MAXLVS
;
159 p
= kmalloc(count
, GFP_KERNEL
);
163 if (read_lba(state
, lba
, (u8
*) p
, count
) < count
) {
170 int aix_partition(struct parsed_partitions
*state
)
176 u32 pp_blocks_size
= 0;
180 struct pvd
*pvd
= NULL
;
182 unsigned short pps_per_lv
;
183 unsigned short pps_found
;
184 unsigned char lv_is_contiguous
;
186 struct lvname
*n
= NULL
;
188 d
= read_part_sector(state
, 7, §
);
190 struct lvm_rec
*p
= (struct lvm_rec
*)d
;
191 u16 lvm_version
= be16_to_cpu(p
->version
);
194 if (lvm_version
== 1) {
195 int pp_size_log2
= be16_to_cpu(p
->pp_size
);
197 pp_bytes_size
= 1 << pp_size_log2
;
198 pp_blocks_size
= pp_bytes_size
/ 512;
199 snprintf(tmp
, sizeof(tmp
),
200 " AIX LVM header version %u found\n",
202 vgda_len
= be32_to_cpu(p
->vgda_len
);
203 vgda_sector
= be32_to_cpu(p
->vgda_psn
[0]);
205 snprintf(tmp
, sizeof(tmp
),
206 " unsupported AIX LVM version %d found\n",
209 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
210 put_dev_sector(sect
);
212 if (vgda_sector
&& (d
= read_part_sector(state
, vgda_sector
, §
))) {
213 struct vgda
*p
= (struct vgda
*)d
;
215 numlvs
= be16_to_cpu(p
->numlvs
);
216 put_dev_sector(sect
);
218 lvip
= kcalloc(state
->limit
, sizeof(struct lv_info
), GFP_KERNEL
);
221 if (numlvs
&& (d
= read_part_sector(state
, vgda_sector
+ 1, §
))) {
222 struct lvd
*p
= (struct lvd
*)d
;
225 n
= alloc_lvn(state
, vgda_sector
+ vgda_len
- 33);
229 for (i
= 0; foundlvs
< numlvs
&& i
< state
->limit
; i
+= 1) {
230 lvip
[i
].pps_per_lv
= be16_to_cpu(p
[i
].num_lps
);
231 if (lvip
[i
].pps_per_lv
)
234 /* pvd loops depend on n[].name and lvip[].pps_per_lv */
235 pvd
= alloc_pvd(state
, vgda_sector
+ 17);
237 put_dev_sector(sect
);
240 int numpps
= be16_to_cpu(pvd
->pp_count
);
241 int psn_part1
= be32_to_cpu(pvd
->psn_part1
);
247 for (i
= 0; i
< numpps
; i
+= 1) {
248 struct ppe
*p
= pvd
->ppe
+ i
;
251 lp_ix
= be16_to_cpu(p
->lp_ix
);
256 lv_ix
= be16_to_cpu(p
->lv_ix
) - 1;
257 if (lv_ix
>= state
->limit
) {
261 lvip
[lv_ix
].pps_found
+= 1;
265 } else if (lv_ix
!= cur_lv_ix
|| lp_ix
!= next_lp_ix
) {
269 if (lp_ix
== lvip
[lv_ix
].pps_per_lv
) {
272 put_partition(state
, lv_ix
+ 1,
273 (i
+ 1 - lp_ix
) * pp_blocks_size
+ psn_part1
,
274 lvip
[lv_ix
].pps_per_lv
* pp_blocks_size
);
275 snprintf(tmp
, sizeof(tmp
), " <%s>\n",
277 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
278 lvip
[lv_ix
].lv_is_contiguous
= 1;
284 for (i
= 0; i
< state
->limit
; i
+= 1)
285 if (lvip
[i
].pps_found
&& !lvip
[i
].lv_is_contiguous
) {
286 char tmp
[sizeof(n
[i
].name
) + 1]; // null char
288 snprintf(tmp
, sizeof(tmp
), "%s", n
[i
].name
);
289 pr_warn("partition %s (%u pp's found) is "
291 tmp
, lvip
[i
].pps_found
);