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 * read_lba(): Read bytes from disk, starting at given LBA
76 * Description: Reads @count bytes from @state->disk into @buffer.
77 * Returns number of bytes read on success, 0 on error.
79 static size_t read_lba(struct parsed_partitions
*state
, u64 lba
, u8
*buffer
,
82 size_t totalreadcount
= 0;
84 if (!buffer
|| lba
+ count
/ 512 > get_capacity(state
->disk
) - 1ULL)
90 unsigned char *data
= read_part_sector(state
, lba
++, §
);
95 memcpy(buffer
, data
, copied
);
98 totalreadcount
+= copied
;
101 return totalreadcount
;
105 * alloc_pvd(): reads physical volume descriptor
109 * Description: Returns pvd on success, NULL on error.
110 * Allocates space for pvd and fill it with disk blocks at @lba
111 * Notes: remember to free pvd when you're done!
113 static struct pvd
*alloc_pvd(struct parsed_partitions
*state
, u32 lba
)
115 size_t count
= sizeof(struct pvd
);
118 p
= kmalloc(count
, GFP_KERNEL
);
122 if (read_lba(state
, lba
, (u8
*) p
, count
) < count
) {
130 * alloc_lvn(): reads logical volume names
134 * Description: Returns lvn on success, NULL on error.
135 * Allocates space for lvn and fill it with disk blocks at @lba
136 * Notes: remember to free lvn when you're done!
138 static struct lvname
*alloc_lvn(struct parsed_partitions
*state
, u32 lba
)
140 size_t count
= sizeof(struct lvname
) * LVM_MAXLVS
;
143 p
= kmalloc(count
, GFP_KERNEL
);
147 if (read_lba(state
, lba
, (u8
*) p
, count
) < count
) {
154 int aix_partition(struct parsed_partitions
*state
)
160 u32 pp_blocks_size
= 0;
164 struct pvd
*pvd
= NULL
;
166 unsigned short pps_per_lv
;
167 unsigned short pps_found
;
168 unsigned char lv_is_contiguous
;
170 struct lvname
*n
= NULL
;
172 d
= read_part_sector(state
, 7, §
);
174 struct lvm_rec
*p
= (struct lvm_rec
*)d
;
175 u16 lvm_version
= be16_to_cpu(p
->version
);
178 if (lvm_version
== 1) {
179 int pp_size_log2
= be16_to_cpu(p
->pp_size
);
181 pp_bytes_size
= 1 << pp_size_log2
;
182 pp_blocks_size
= pp_bytes_size
/ 512;
183 snprintf(tmp
, sizeof(tmp
),
184 " AIX LVM header version %u found\n",
186 vgda_len
= be32_to_cpu(p
->vgda_len
);
187 vgda_sector
= be32_to_cpu(p
->vgda_psn
[0]);
189 snprintf(tmp
, sizeof(tmp
),
190 " unsupported AIX LVM version %d found\n",
193 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
194 put_dev_sector(sect
);
196 if (vgda_sector
&& (d
= read_part_sector(state
, vgda_sector
, §
))) {
197 struct vgda
*p
= (struct vgda
*)d
;
199 numlvs
= be16_to_cpu(p
->numlvs
);
200 put_dev_sector(sect
);
202 lvip
= kcalloc(state
->limit
, sizeof(struct lv_info
), GFP_KERNEL
);
205 if (numlvs
&& (d
= read_part_sector(state
, vgda_sector
+ 1, §
))) {
206 struct lvd
*p
= (struct lvd
*)d
;
209 n
= alloc_lvn(state
, vgda_sector
+ vgda_len
- 33);
213 for (i
= 0; foundlvs
< numlvs
&& i
< state
->limit
; i
+= 1) {
214 lvip
[i
].pps_per_lv
= be16_to_cpu(p
[i
].num_lps
);
215 if (lvip
[i
].pps_per_lv
)
218 /* pvd loops depend on n[].name and lvip[].pps_per_lv */
219 pvd
= alloc_pvd(state
, vgda_sector
+ 17);
221 put_dev_sector(sect
);
224 int numpps
= be16_to_cpu(pvd
->pp_count
);
225 int psn_part1
= be32_to_cpu(pvd
->psn_part1
);
231 for (i
= 0; i
< numpps
; i
+= 1) {
232 struct ppe
*p
= pvd
->ppe
+ i
;
235 lp_ix
= be16_to_cpu(p
->lp_ix
);
240 lv_ix
= be16_to_cpu(p
->lv_ix
) - 1;
241 if (lv_ix
>= state
->limit
) {
245 lvip
[lv_ix
].pps_found
+= 1;
249 } else if (lv_ix
!= cur_lv_ix
|| lp_ix
!= next_lp_ix
) {
253 if (lp_ix
== lvip
[lv_ix
].pps_per_lv
) {
256 put_partition(state
, lv_ix
+ 1,
257 (i
+ 1 - lp_ix
) * pp_blocks_size
+ psn_part1
,
258 lvip
[lv_ix
].pps_per_lv
* pp_blocks_size
);
259 snprintf(tmp
, sizeof(tmp
), " <%s>\n",
261 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
262 lvip
[lv_ix
].lv_is_contiguous
= 1;
268 for (i
= 0; i
< state
->limit
; i
+= 1)
269 if (lvip
[i
].pps_found
&& !lvip
[i
].lv_is_contiguous
) {
270 char tmp
[sizeof(n
[i
].name
) + 1]; // null char
272 snprintf(tmp
, sizeof(tmp
), "%s", n
[i
].name
);
273 pr_warn("partition %s (%u pp's found) is "
275 tmp
, lvip
[i
].pps_found
);