Class: Yast::BootStorageClass

Inherits:
Module
  • Object
show all
Includes:
Logger
Defined in:
src/modules/BootStorage.rb

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Instance Attribute Details

- (Object) device_map

Returns the value of attribute device_map



28
29
30
# File 'src/modules/BootStorage.rb', line 28

def device_map
  @device_map
end

Instance Method Details

- (Object) available_swap_partitions

Get map of swap partitions

Returns:

  • a map where key is partition name and value its size in KB



481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
# File 'src/modules/BootStorage.rb', line 481

def available_swap_partitions
  tm = Storage.GetTargetMap
  ret = {}
  tm.each_value do |v|
    partitions = v["partitions"] || []
    partitions.select! do |p|
      p["mount"] == "swap" && !p["delete"]
    end
    partitions.each do |s|
      # bnc#577127 - Encrypted swap is not properly set up as resume device
      if s["crypt_device"] && !s["crypt_device"].empty?
        dev = s["crypt_device"]
      else
        dev = s["device"]
      end
      ret[dev] = s["size_k"] || 0
    end
  end

  log.info "Available swap partitions: #{ret}"
  ret
end

- (Object) can_boot_from_partition



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'src/modules/BootStorage.rb', line 313

def can_boot_from_partition
  tm = Storage.GetTargetMap
  partition = @BootPartitionDevice || @RootPartitionDevice

  part = Storage.GetPartition(tm, partition)

  if !part
    log.error "cannot find partition #{partition}"
    return false
  end

  fs = part["used_fs"]
  log.info "FS for boot partition #{fs}"

  # cannot install stage one to xfs as it doesn't have reserved space (bnc#884255)
  fs != :xfs
end

- (Object) checkCallingDiskInfo

Check if function was called or storage change partitionig of disk. It is usefull fo using cached data about disk. Data is send to perl-Bootloader and it includes info about partitions, multi path and md-raid

Returns:

  • false if it is posible use cached data



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'src/modules/BootStorage.rb', line 104

def checkCallingDiskInfo
  # fix for problem with unintialized storage library in AutoYaST mode
  # bnc #464090
  if Mode.config && !@storage_initialized
    @storage_initialized = true
    log.info "Init storage library in yast2-bootloader"
    Storage.InitLibstorage(true)
  end
  if @disk_change_time_checkCallingDiskInfo != Storage.GetTargetChangeTime ||
      @partinfo.empty?
    # save last change time from storage
    @disk_change_time_checkCallingDiskInfo = Storage.GetTargetChangeTime
    log.info "disk was changed by storage or partinfo is empty"
    log.info "generate partinfo, md_info, mountpoints and multipath_mapping"
    return true
  else
    log.info "Skip genarating partinfo, md_info, mountpoints and multipath_mapping"
    return false
  end
end

- (Boolean) checkDifferentDisks(devices)

FATE#305008: Failover boot configurations for md arrays with redundancy Check if devices has same partition number and if they are from different disks

Parameters:

  • list (string)

    list of devices

Returns:

  • (Boolean)

    true on success



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'src/modules/BootStorage.rb', line 250

def checkDifferentDisks(devices)
  disks = []
  no_partition = ""
  devices.each do |dev|
    p_dev = Storage.GetDiskPartition(dev)
    disk = p_dev["disk"]
    if disks.include?(disk)
      log.info "Same disk for md array -> disable synchronize md arrays"
      return false
    else
      disks <<  disk
    end
    # add disk from partition to md_physical_disks
    @md_physical_disks << disk unless @md_physical_disks.include?(disk)

    no_p = p_dev["nr"].to_s
    if no_p == ""
      log.error "Wrong number of partition: #{dev} from Storage::GetDiskPartition: #{p_dev}"
      return false
    end
    if no_partition == ""
      no_partition = no_p
    elsif no_partition != no_p
      log.info "Different number of partitions -> disable synchronize md arrays"
      return false
    end
  end

  true
end

- (Object) checkMDDevices(tm, device)

FATE#305008: Failover boot configurations for md arrays with redundancy Check if device are build from 2 partitions with same number but from different disks

Parameters:

  • tm (Hash{String => map})

    taregte map from storage

  • device (String)

    (md device)

Returns:

  • true if device is from 2 partisions with same number and different disks



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'src/modules/BootStorage.rb', line 287

def checkMDDevices(tm, device)
  ret = false
  tm_dm = tm["/dev/md"] || {}

  # find partitions in target map
  (tm_dm["partitions"] || []).each do |p|
    next unless p["device"] == device

    if p["raid_type"] == "raid1"
      p_devices = p["devices"] || []
      if p_devices.size == 2 # TODO: why only 2? it do not make sense
        ret = checkDifferentDisks(p_devices)
      else
        log.info "Device: #{device} doesn't contain 2 partitions: #{p_devices}"
      end
    else
      log.info "Device: #{device} is not on raid1: #{p["raid_type"]}"
    end
  end

  log.info "device: #{device} is based on md_physical_disks: #{@md_physical_disks}"\
    "is #{ ret ? "valid" : "invalid" } for enable redundancy"

  ret
end

- (Object) detect_disks

Sets properly boot, root and mbr disk.

Returns:

  • :empty if bl devices are empty, :invalid if storage changed and :ok if everything is fine



418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'src/modules/BootStorage.rb', line 418

def detect_disks
  # The AutoYaST config mode does access to the system.
  # bnc#942360
  return :ok if Mode.config

  mp = Storage.GetMountPoints

  mountdata_boot = mp["/boot"] || mp["/"]
  mountdata_root = mp["/"]

  log.info "mountPoints #{mp}"
  log.info "mountdata_boot #{mountdata_boot}"

  @RootPartitionDevice = mountdata_root ? mountdata_root.first || "" : ""
  raise "No mountpoint for / !!" if @RootPartitionDevice.empty?

  # if /boot changed, re-configure location
  @BootPartitionDevice = mountdata_boot.first

  # get extended partition device (if exists)
  @ExtendedPartitionDevice = extended_partition_for(@BootPartitionDevice)

  if BootCommon.mbrDisk == "" || BootCommon.mbrDisk.nil?
    # mbr detection.
    BootCommon.mbrDisk = BootCommon.FindMBRDisk
  end

  # device map may be implicitly proposed in FindMBRDisk above
  # - but not always...
  device_map.propose if device_map.empty?

  # if no bootloader devices have been set up, or any of the set up
  # bootloader devices have become unavailable, then re-propose the
  # bootloader location.
  bldevs = BootCommon.GetBootloaderDevices

  return :empty if bldevs.empty?

  all_boot_partitions = possible_locations_for_stage1
  invalid = bldevs.any? do |dev|
    !all_boot_partitions.include?(dev)
  end

  invalid ? :invalid : :ok
end

- (Array) devices_for_redundant_boot

FATE#305008: Failover boot configurations for md arrays with redundancy Function check partitions and set redundancy available if partitioning of disk allows it. It means if md array is based on 2 partitions with same number but 2 different disks E.g. /dev/md0 is from /dev/sda1 and /dev/sb1 and /dev/md0 is “/” There is possible only boot from MBR (GRUB not generic boot code)

Returns:

  • (Array)

    Array of devices that can be used to redundancy boot



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'src/modules/BootStorage.rb', line 340

def devices_for_redundant_boot
  tm = Storage.GetTargetMap

  if !tm["/dev/md"]
    log.info "Doesn't include md raid"
    return []
  end

  boot_devices = [@BootPartitionDevice]
  if @BootPartitionDevice != @RootPartitionDevice
    boot_devices << @RootPartitionDevice
  end
  boot_devices << @ExtendedPartitionDevice
  boot_devices.delete_if { |d| d.nil? || d.empty? }

  log.info "Devices for analyse of redundacy md array: #{boot_devices}"

  boot_devices.each do |dev|
    ret = checkMDDevices(tm, dev)
    # only log if device is not suitable, otherwise md redundancy is not
    # allowed even if there is some suitable device (bnc#917025)
    log.info "Skip enable redundancy for device #{dev}" unless ret
  end

  @md_physical_disks
end

- (Object) DisksOrder

Get the order of disks according to BIOS mapping

Returns:

  • a list of all disks in the order BIOS sees them



187
188
189
190
191
# File 'src/modules/BootStorage.rb', line 187

def DisksOrder
  @device_map.propose if @device_map.empty?

  @device_map.disks_order
end

- (Object) extended_partition_for(device)

Get extended partition for given partition or disk



232
233
234
235
236
237
238
239
240
241
242
243
# File 'src/modules/BootStorage.rb', line 232

def extended_partition_for(device)
  disk_partition = Yast::Storage.GetDiskPartition(device)
  return nil unless disk_partition["disk"]

  target_map = Yast::Storage.GetTargetMap
  disk_map = target_map[disk_partition["disk"]] || {}
  partitions = disk_map["partitions"] || []
  ext_part = partitions.find { |p| p["type"] == :extended }
  return nil unless ext_part

  ext_part["device"]
end

- (Object) InitDiskInfo

Function init data for perl-Bootloader about disk It means fullfil md_info, multipath_mapping, partinfo and mountpoints



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'src/modules/BootStorage.rb', line 129

def InitDiskInfo
  return unless checkCallingDiskInfo

  # delete variables for perl-Bootloader
  @md_info = {}

  tm = Storage.GetTargetMap

  @multipath_mapping = mapRealDevicesToMultipath
  @mountpoints = Builtins.mapmap(Storage.GetMountPoints) do |k, v|
    # detect all raid1 md devices and mark them in md_info
    device = v[0]
    @md_info[device] = [] if v[3] == "raid1"
    { k => device }
  end
  # filter out temporary mount points from installation

  tmpdir = SCR.Read(path(".target.tmpdir"))
  @mountpoints = Builtins.filter(@mountpoints) do |k, v|
    v.is_a?(::String) && !k.start_with?(tmpdir)
  end

  log.info "Detected mountpoints: #{@mountpoints}"

  @partinfo = tm.reduce([]) do |res, i|
    disk, info = i
    next res if [:CT_LVM, :CT_EVMS].include?(info["type"])
    partitions = info["partitions"]
    # disk do not have to be partitioned, so skip it in such case
    next res unless partitions

    parts = partitions.map do |p|
      raid = p["used_by_type"] == :UB_MD ? p["used_by_device"] : nil
      device = p["device"] || ""
      # We only pass along RAID1 devices as all other causes
      # severe breakage in the bootloader stack
      @md_info[raid] << device if raid && @md_info.include?(raid)

      nr = (p["nr"] || 0).to_s
      region = p.fetch("region", [])
      [
        device,
        disk,
        nr,
        p["fsid"].to_i.to_s,
        p["fstype"] || "unknown",
        p["type"] || "nil",
        (region[0] || 0).to_s,
        (region[1] || 0).to_s,
        ::Bootloader::UdevMapping.to_mountby_device(device)
      ]
    end
    res.concat(parts)
  end
end

- (Object) main



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'src/modules/BootStorage.rb', line 30

def main
  textdomain "bootloader"

  Yast.import "BootCommon"
  Yast.import "Storage"
  Yast.import "StorageDevices"
  Yast.import "Arch"
  Yast.import "Mode"

  # Saved change time from target map - only for checkCallingDiskInfo()
  @disk_change_time_checkCallingDiskInfo = nil

  # Storage locked
  @storage_initialized = false

  # device mapping between real devices and multipath
  @multipath_mapping = {}

  # mountpoints for perl-Bootloader
  @mountpoints = {}

  # list of all partitions for perl-Bootloader
  @partinfo = []

  # information about MD arrays for perl-Bootloader
  @md_info = {}

  # device mapping between Linux and firmware
  @device_map = ::Bootloader::DeviceMap.new

  # string sepresenting device name of /boot partition
  # same as RootPartitionDevice if no separate /boot partition
  @BootPartitionDevice = ""

  # string representing device name of / partition
  @RootPartitionDevice = ""

  # string representing device name of extended partition
  @ExtendedPartitionDevice = ""

  # FATE#305008: Failover boot configurations for md arrays with redundancy
  # list <string> includes physical disks used for md raid

  @md_physical_disks = []
end

- (Object) mapRealDevicesToMultipath

FIXME: grub only



84
85
86
87
88
89
90
91
92
93
94
95
# File 'src/modules/BootStorage.rb', line 84

def mapRealDevicesToMultipath
  ret = {}
  tm = Storage.GetTargetMap
  tm.each do |disk, disk_info|
    next if disk_info["type"] != :CT_DMMULTIPATH

    devices = disk_info["devices"] || []
    devices.each { |d| ret[d] = disk }
  end

  ret
end

- (Object) Md2Partitions(md_device)

Converts the md device to the list of devices building it

Parameters:

  • md_device (String)

    string md device

Returns:

  • a map of devices from device name to BIOS ID or empty hash if not detected) building the md device



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'src/modules/BootStorage.rb', line 371

def Md2Partitions(md_device)
  ret = {}
  tm = Storage.GetTargetMap
  tm.each_pair do |_disk, descr|
    bios_id = (descr["bios_id"] || 256).to_i # maximum + 1 (means: no bios_id found)
    partitions = descr["partitions"] || []
    partitions.each do |partition|
      if partition["used_by_device"] == md_device
        ret[partition["device"]] = bios_id
      end
    end
  end
  log.info "Partitions building #{md_device}: #{ret}"

  ret
end

- (Object) possible_locations_for_stage1

Returns list of partitions and disks. Requests current partitioning from yast2-storage and creates list of partition and disks usable for grub stage1



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'src/modules/BootStorage.rb', line 195

def possible_locations_for_stage1
  devices = Storage.GetTargetMap

  all_disks = devices.keys
  # Devices which is not in device map cannot be used to boot
  all_disks.select! { |d| device_map.contain_disk?(d) }

  disks_for_stage1 = all_disks.select do |d|
    [:CT_DISK, :CR_DMRAID].include?(devices[d]["type"])
  end

  partitions = []

  devices.each do |k, v|
    next unless all_disks.include?(k)

    partitions.concat(v["partitions"] || [])
  end

  partitions.delete_if do |p|
    p["delete"]
  end

  partitions.select! do |p|
    [:primary, :extended, :logical, :sw_raid].include?(p["type"]) &&
      (p["used_fs"] || p["detected_fs"]) != :xfs &&
      ["Linux native", "Extended", "Linux RAID", "MD RAID", "DM RAID"].include?(p["fstype"])
  end

  res = partitions.map { |p| p["device"] || "" }
  res.concat(disks_for_stage1)
  res.delete_if(&:empty?)

  res
end

- (Object) prep_partitions



464
465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'src/modules/BootStorage.rb', line 464

def prep_partitions
  target_map = Storage.GetTargetMap

  partitions = target_map.reduce([]) do |parts, pair|
    parts.concat(pair[1]["partitions"] || [])
  end

  prep_partitions = partitions.select do |partition|
    [0x41, 0x108].include? partition["fsid"]
  end

  y2milestone "detected prep partitions #{prep_partitions.inspect}"
  prep_partitions.map { |p| p["device"] }
end

- (Object) real_disks_for_partition(partition)

returns disk names where partition lives



389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'src/modules/BootStorage.rb', line 389

def real_disks_for_partition(partition)
  # FIXME: handle somehow if disk are in logical raid
  partitions = Md2Partitions(partition).keys
  partitions = [partition] if partitions.empty?
  res = partitions.map do |part|
    Storage.GetDiskPartition(part)["disk"]
  end
  res.uniq!
  # handle LVM disks
  tm = Storage.GetTargetMap
  res = res.each_with_object([]) do |disk, ret|
    disk_meta = tm[disk]
    next unless disk_meta

    if disk_meta["lvm2"]
      devices = (disk_meta["devices"] || []) + (disk_meta["devices_add"] || [])
      disks = devices.map { |d| real_disks_for_partition(d) }
      ret.concat(disks.flatten)
    else
      ret << disk
    end
  end

  res.uniq
end