cookbooks/fb_sdparm/resources/default.rb (105 lines of code) (raw):
#
# vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
#
# Copyright (c) 2018-present, Facebook, Inc.
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
default_action :set
resource_name :fb_sdparm
provides :fb_sdparm
def get_sdparm_value(param, device)
cmd = Mixlib::ShellOut.new("sdparm --get #{param} /dev/#{device}").run_command
cmd.error!
output = cmd.stdout
# Match anything besides whitespace between '=' and paren
re = /^#{param}\s+(\w+)\s/m
match_obj = re.match(output)
unless match_obj
fail 'fb_sdparm: could not parse the output of sdparm'
end
match_data = match_obj[1]
if match_data =~ /^\s*$/
fail "fb_sdparm: could not get sdparm value for: #{param}"
end
match_data.to_s.strip
end
def set_sdparm_value(param, value, device, device_type)
command = "sdparm --set #{param}=#{value}"
# SATA devices do not support --save
unless device_type == 'ATA'
command << ' --save'
end
command << " /dev/#{device}"
s = Mixlib::ShellOut.new(command).run_command
s.error!
new_val = get_sdparm_value(param, device)
if new_val.to_s != value.to_s
fail "fb_sdparm: drive still reports value as #{new_val}, " +
"should be #{value}!"
end
Chef::Log.info("fb_sdparm: #{device}: set sdparm #{param} to #{value}.")
end
def cache_type_path_for_device(device)
::Dir.glob(
"/sys/block/#{device}/device/scsi_disk/*/cache_type",
).first
end
def get_cache_type_desired_and_path(device)
# key is a 2-item array of WCE, RCD
cache_type_expected_values = {
[0, 0] => 'write through',
[0, 1] => 'none',
[1, 0] => 'write back',
[1, 1] => 'write back, no read (daft)',
}
wce = get_sdparm_value('WCE', device).to_i
rcd = get_sdparm_value('RCD', device).to_i
desired_cache_type = cache_type_expected_values[[wce, rcd]]
cache_type_path = cache_type_path_for_device(device)
[desired_cache_type, cache_type_path]
end
action :set do
param_whitelist = [
'RCD',
'WCE',
]
in_maint_disks = FB::Fstab.get_in_maint_disks
Chef::Log.debug("in_maint_disks: #{in_maint_disks}")
root_dev = node.device_of_mount('/')
disks = node['block_device'].to_hash.reject do |dev, attrs|
['ram', 'loop', 'dm-'].include?(dev.delete('0-9')) ||
(root_dev && root_dev.start_with?(dev)) ||
dev.start_with?('nvme') ||
dev.start_with?('md') ||
dev.start_with?('fio') ||
dev.start_with?('sr') ||
attrs['model'] == 'XP6210-4B2048' || # nytro flash card
in_maint_disks.include?("/dev/#{dev}")
end
Chef::Log.debug("disks: #{disks}")
rotational_settings = node['fb_sdparm']['settings']['rotational'] ?
node['fb_sdparm']['settings']['rotational'].to_hash :
{}
non_rotational_settings = node['fb_sdparm']['settings']['non-rotational'] ?
node['fb_sdparm']['settings']['non-rotational'].to_hash :
{}
disks.each do |disk, details|
if details['rotational'].to_i == 1
settings = rotational_settings
elsif details['rotational'].to_i.zero?
settings = non_rotational_settings
else
# something is very wrong
fail "fb_sdparm: disk #{disk} has no rotational value!"
end
settings.each do |param, desired_value|
unless param_whitelist.include?(param)
# do not let someone silently fail to set value due to typos
fail "fb_sdparm: param #{param} is not yet supported by fb_sdparm!"
end
current_value = get_sdparm_value(param, disk)
# Don't bother setting it if it's already correct
if current_value.to_s == desired_value.to_s
Chef::Log.debug("fb_sdparm: #{param} value already set to " +
"#{desired_value}.")
else
converge_by 'setting sdparm value' do
set_sdparm_value(param, desired_value, disk, details['vendor'])
end
end
end
desired_cache_type, cache_type_path = get_cache_type_desired_and_path(disk)
fb_sysfs cache_type_path do
type :string
value desired_cache_type + "\n"
end
end
end