1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2012-2013 Philippe De Muyter <phdm@macqel.be>
12 char lvm_id
[4]; /* "_LVM" */
18 __be16 pp_size
; /* log2(pp_size) */
56 unsigned short res8
[12];
68 #define LVM_MAXLVS 256
71 * last_lba(): return number of last logical block of device
74 * Description: Returns last LBA value on success, 0 on error.
75 * This is stored (by sd and ide-geometry) in
76 * the part[0] entry for this disk, and is the number of
77 * physical sectors available on the disk.
79 static u64
last_lba(struct block_device
*bdev
)
81 if (!bdev
|| !bdev
->bd_inode
)
83 return (bdev
->bd_inode
->i_size
>> 9) - 1ULL;
87 * read_lba(): Read bytes from disk, starting at given LBA
93 * Description: Reads @count bytes from @state->bdev into @buffer.
94 * Returns number of bytes read on success, 0 on error.
96 static size_t read_lba(struct parsed_partitions
*state
, u64 lba
, u8
*buffer
,
99 size_t totalreadcount
= 0;
101 if (!buffer
|| lba
+ count
/ 512 > last_lba(state
->bdev
))
107 unsigned char *data
= read_part_sector(state
, lba
++, §
);
112 memcpy(buffer
, data
, copied
);
113 put_dev_sector(sect
);
115 totalreadcount
+= copied
;
118 return totalreadcount
;
122 * alloc_pvd(): reads physical volume descriptor
126 * Description: Returns pvd on success, NULL on error.
127 * Allocates space for pvd and fill it with disk blocks at @lba
128 * Notes: remember to free pvd when you're done!
130 static struct pvd
*alloc_pvd(struct parsed_partitions
*state
, u32 lba
)
132 size_t count
= sizeof(struct pvd
);
135 p
= kmalloc(count
, GFP_KERNEL
);
139 if (read_lba(state
, lba
, (u8
*) p
, count
) < count
) {
147 * alloc_lvn(): reads logical volume names
151 * Description: Returns lvn on success, NULL on error.
152 * Allocates space for lvn and fill it with disk blocks at @lba
153 * Notes: remember to free lvn when you're done!
155 static struct lvname
*alloc_lvn(struct parsed_partitions
*state
, u32 lba
)
157 size_t count
= sizeof(struct lvname
) * LVM_MAXLVS
;
160 p
= kmalloc(count
, GFP_KERNEL
);
164 if (read_lba(state
, lba
, (u8
*) p
, count
) < count
) {
171 int aix_partition(struct parsed_partitions
*state
)
177 u32 pp_blocks_size
= 0;
181 struct pvd
*pvd
= NULL
;
183 unsigned short pps_per_lv
;
184 unsigned short pps_found
;
185 unsigned char lv_is_contiguous
;
187 struct lvname
*n
= NULL
;
189 d
= read_part_sector(state
, 7, §
);
191 struct lvm_rec
*p
= (struct lvm_rec
*)d
;
192 u16 lvm_version
= be16_to_cpu(p
->version
);
195 if (lvm_version
== 1) {
196 int pp_size_log2
= be16_to_cpu(p
->pp_size
);
198 pp_bytes_size
= 1 << pp_size_log2
;
199 pp_blocks_size
= pp_bytes_size
/ 512;
200 snprintf(tmp
, sizeof(tmp
),
201 " AIX LVM header version %u found\n",
203 vgda_len
= be32_to_cpu(p
->vgda_len
);
204 vgda_sector
= be32_to_cpu(p
->vgda_psn
[0]);
206 snprintf(tmp
, sizeof(tmp
),
207 " unsupported AIX LVM version %d found\n",
210 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
211 put_dev_sector(sect
);
213 if (vgda_sector
&& (d
= read_part_sector(state
, vgda_sector
, §
))) {
214 struct vgda
*p
= (struct vgda
*)d
;
216 numlvs
= be16_to_cpu(p
->numlvs
);
217 put_dev_sector(sect
);
219 lvip
= kcalloc(state
->limit
, sizeof(struct lv_info
), GFP_KERNEL
);
222 if (numlvs
&& (d
= read_part_sector(state
, vgda_sector
+ 1, §
))) {
223 struct lvd
*p
= (struct lvd
*)d
;
226 n
= alloc_lvn(state
, vgda_sector
+ vgda_len
- 33);
230 for (i
= 0; foundlvs
< numlvs
&& i
< state
->limit
; i
+= 1) {
231 lvip
[i
].pps_per_lv
= be16_to_cpu(p
[i
].num_lps
);
232 if (lvip
[i
].pps_per_lv
)
235 /* pvd loops depend on n[].name and lvip[].pps_per_lv */
236 pvd
= alloc_pvd(state
, vgda_sector
+ 17);
238 put_dev_sector(sect
);
241 int numpps
= be16_to_cpu(pvd
->pp_count
);
242 int psn_part1
= be32_to_cpu(pvd
->psn_part1
);
248 for (i
= 0; i
< numpps
; i
+= 1) {
249 struct ppe
*p
= pvd
->ppe
+ i
;
252 lp_ix
= be16_to_cpu(p
->lp_ix
);
257 lv_ix
= be16_to_cpu(p
->lv_ix
) - 1;
258 if (lv_ix
>= state
->limit
) {
262 lvip
[lv_ix
].pps_found
+= 1;
266 } else if (lv_ix
!= cur_lv_ix
|| lp_ix
!= next_lp_ix
) {
270 if (lp_ix
== lvip
[lv_ix
].pps_per_lv
) {
273 put_partition(state
, lv_ix
+ 1,
274 (i
+ 1 - lp_ix
) * pp_blocks_size
+ psn_part1
,
275 lvip
[lv_ix
].pps_per_lv
* pp_blocks_size
);
276 snprintf(tmp
, sizeof(tmp
), " <%s>\n",
278 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
279 lvip
[lv_ix
].lv_is_contiguous
= 1;
285 for (i
= 0; i
< state
->limit
; i
+= 1)
286 if (lvip
[i
].pps_found
&& !lvip
[i
].lv_is_contiguous
) {
287 char tmp
[sizeof(n
[i
].name
) + 1]; // null char
289 snprintf(tmp
, sizeof(tmp
), "%s", n
[i
].name
);
290 pr_warn("partition %s (%u pp's found) is "
292 tmp
, lvip
[i
].pps_found
);