Reset /proc/sys/vm/drop_caches to default value 0 - linux

Recently I tried to empty the buffers cache on a Debian webserver. The command I used was:
free && sync && echo 3 > /proc/sys/vm/drop_caches && free
So far so good, running cat /proc/sys/vm/drop_caches prints a value of 3.
When I try to reset the value to 0 with sync && echo 0 > /proc/sys/vm/drop_caches, this error shows:
bash: echo: write error: Invalid argument
Which is due to drop_caches being a command, not a variable to be set. I found this:
sudo sysctl -w vm.drop_caches=3
It immediately clears the pagecache, dentries and inodes and clears again only if you call sysctl -w again, there is no need to apparently set it back to 0 in an explicit manner. The command sysctl is not natively supported on Debian so I'm looking for an alternative command, more precisely:
How to reset drop_caches or immediately empty the cache to reset the value to 0?

The values 1-3 are just one time trigger for action. There is no value 0.
sysctl is in package procps .
apt install procps

To disable them, echo 4 (bit 2) into drop_caches.
from https://www.kernel.org/doc/Documentation/sysctl/vm.txt

Related

The first char of the string from a text file be eat after the shell while loop into second interate

It is a very strange question.
I am trying to use turbostat(from linux kernel: linux/tools/power/x86/turbostat) to log the energy usage for some program.
for simplify, I use the stress(you can get it: sudo apt install stress) as the program been test.
I have 4 sub-folders, they are 1/, 2/, 3/, 4/, each folder have a test suite need to run, I have create a text file which have the test list.
the turbostat link:
https://github.com/torvalds/linux/tree/master/tools/power/x86/turbostat
the turbostat was build and copy to /usr/bin, and run: sudo chmod u+s turbostat in /usr/bin for permission.
my folder struct:
topfolder
|-testlist.txt
|-runall.sh
|-1/
|-2/
|-3/
|-4/
the runall.sh:
# run loop
reset
_dir=$(pwd)
while IFS= read -r line; do
echo ''
echo $line
cd $line
echo stress --cpu 1 --timeout 5 > doit.sh
turbostat -S -i 0.5 --show Bzy_MHz,CorWatt,PkgWatt -o $line.tsv&
sh doit.sh
cd $_dir
done < "testlist.txt"
the content of testlist.txt:
1
2
3
4
output of runall.sh:
1
stress: info: [1729] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
turbostat: Insanely slow TSC rate, TSC stops in idle?
You can disable all c-states by booting with "idle=poll"
or just the deep ones with "processor.max_cstate=1"
stress: info: [1729] successful run completed in 5s
[2]+ Exit 253 turbostat -S -i 0.5 --show Bzy_MHz,CorWatt,PkgWatt -o $line.tsv
stress: info: [1735] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
stress: info: [1735] successful run completed in 5s
at the first interate, the $line is "1", but in the next interate, $line would be a blank string.
if change the testlist.txt to:
1
12
13
14
the $line would be 1 2 3 4, the first char been eat from second interate.
why this happen? and how can I fix it?
My OS: ubuntu 22.04.1 with kernel 5.19.3
update:
when change:
turbostat -i 0.5 --show Bzy_MHz,CorWatt,PkgWatt -o $line.tsv &
sh doit.sh
to:
turbostat -i 0.5 --show Bzy_MHz,CorWatt,PkgWatt -o $line.tsv sh doit.sh
the while loop run normal,but, I can not get the log for each 0.5 second(-i 0.5) which what I need, turbostat only output a avg results.
I think turbostat with "&" would eat the first char ?
update 2:
Thanks William Pursell, add yes|Q before turbostat... does allow the loop run normal.
There is still a question, turbostat can not output the results what I expect . Maybe I need to open another question for it.

Linux: Quiet mode and how to make command wait to finish before next

If i do a command like say
yum install -y -q packageX
How do i ensure that it waits for finish before doing the next command?
My goal is to have as little unnecessary output as possible but to do each command sequentially with each completing
Linux commands are generally already silent unless there is a problem, that way you only have to pay attention if paying attention is required. Some commands have options to silence their useful and non-problematic output, use man COMMAND_NAME for that or check out TL;DR pages here which are like man but beginner friendly: https://tldr.sh/
For your specific case here you're already using the silenced version of yum as you've passed it the -q flag. The man docs for yum, man yum or online (http://man7.org/linux/man-pages/man8/yum.8.html) state that -q
-q, --quiet
Run without output.
As for the commands:
Use && to chain commands where the success (specifically if the command returns 0 which is often attributed to success) of the previous command is required for the next to be executed.
Here's an example:
cd ./foo && ls
This translates as: attempt to change directory into the folder foo in the current directory, if-and-only-if that succeeds (returns 0) run ls. If foo doesn't exist or it otherwise cannot change directory into foo then ls will not run.
In your case if you wanted to run a command only if that package of yours successfully installed you would do the following where ls is a command that is perhaps more interesting in this case.
yum install -y -q packageX && ls
Just for completeness as conversations about && often bring about ;, if you don't care whether the last command completes successfully (returns 0) and just want to chain commands use ; instead.
cd ./foo; ls
Now even if cd ./foo fails the ls will still execute.

How to detect OS and load ZSH settings conditionally?

I use several different OS's at home and work and I want to be able to load platorm-specific ZSH settings conditionally, depending on which OS I'm using at the given moment.
I tried this but it doesn't load everything I expect:
# Condtitional loading of zsh settings per platform
if command apt > /dev/null; then
source $ZSH_CUSTOM/os/debian.zsh
elif command systemctl > /dev/null; then
source $ZSH_CUSTOM/os/systemd.zsh
elif command freebsd-version > /dev/null; then
source $ZSH_CUSTOM/os/freebsd.zsh
elif [[ `uname` == "Darwin" ]]; then
source $ZSH_CUSTOM/os/mac.zsh
elif command kubectl > /dev/null; then
source $ZSH_CUSTOM/os/kubernetes.zsh
else
echo 'Unknown OS!'
fi
What is the best way to do this detection and what I'm doing wrong?
I know this approach of mine doesn't work as when I run zsh -o SOURCE_TRACE, it doesn't show all desired files sourced.
Thanks in advance!
Revised Answer (2020-Feb-09)
Thanks to #Cyberbeni for reminding me that apt on macOS would incorrectly match the system Java runtime's Annotation Processing Tool. Rolling up the necessary changes, we now have:
# What OS are we running?
if [[ $(uname) == "Darwin" ]]; then
source "$ZSH_CUSTOM"/os/mac.zsh
elif command -v freebsd-version > /dev/null; then
source "$ZSH_CUSTOM"/os/freebsd.zsh
elif command -v apt > /dev/null; then
source "$ZSH_CUSTOM"/os/debian.zsh
else
echo 'Unknown OS!'
fi
# Do we have systemd on board?
if command -v systemctl > /dev/null; then
source "$ZSH_CUSTOM"/os/systemd.zsh
fi
# Ditto Kubernetes?
if command -v kubectl > /dev/null; then
source "$ZSH_CUSTOM"/os/kubernetes.zsh
fi
Original answer
I answered exactly the same question on Reddit here, so to close the loop, here's what I wrote:
Your current logic literally says that, for instance, a Debian system cannot possibly run systemd or Kubernetes, which is clearly untrue. That's exactly what if...elif...else...fi implements: mutual exclusivity.
It looks to me like only the OS-specific tests need to be mutually exclusive, so you're probably looking at something like:
# What OS are we running?
if command apt > /dev/null; then
source $ZSH_CUSTOM/os/debian.zsh
elif command freebsd-version > /dev/null; then
source $ZSH_CUSTOM/os/freebsd.zsh
elif [[ `uname` == "Darwin" ]]; then
source $ZSH_CUSTOM/os/mac.zsh
else
echo 'Unknown OS!'
fi
# Do we have systemd on board?
if command systemctl > /dev/null; then
source $ZSH_CUSTOM/os/systemd.zsh
fi
# Ditto Kubernetes?
if command kubectl > /dev/null; then
source $ZSH_CUSTOM/os/kubernetes.zsh
fi
UPDATE: Actually, I didn't look closely enough at your code, and you're also calling command wrong. All your invocations should be of the form:
if command -v <cmd_name> > /dev/null
which returns success if <cmd_name> is found in your PATH. command <cmd_name> actually runs <cmd_name> and returns its exit status, which can return a failure exit code (i.e. false negative) due to lack of appropriate arguments.
Verifying an OS is system dependent. You can use the package managers to verify a certain distribution, but this not desired, since there are certainly other distributions which the same package manager as well.
You can try to use lsb_release and grep on the correct distribution. Or use uname.
Which OS'es do not load in your script, and which do?
Also, take a look here

How to create a Kernel panic in RHEL without rebooting after panic

I need to create kernel panic and I tried following
sysctl kernel.panic=0 && echo c > /proc/sysrq-trigger
When I ran the commands above. I see system always reboots. I need system to be in panic mode without rebooting
Use -w option when you want to change a sysctl setting under RHEL.
Multiple commands example:
> sysctl -w kernel.panic="0"
> echo c > /proc/sysrq-trigger
Notice that if you want to preserve kernel settings after reboot, it's always better to add them to the /etc/sysctl.conf file. However the quickly setting method maybe enough for your testing requirments.
Also make sure you don't paste both commands "sysctl -w kernel.panic=0 echo c > /proc/sysrq-trigger" together. (I'm always giving this recommendation when i see multiple shell commands posted together, like i see in your question). Or use && operator to execute the next command like this:
Single line example:
sysctl -w kernel.panic="0" && echo c > /proc/sysrq-trigger

Simulate a faulty block device with read errors?

I'm looking for an easier way to test my application against faulty block devices that generate i/o read errors when certain blocks are read. Trying to use a physical hard drive with known bad blocks is a pain and I would like to find a software solution if one exists.
I did find the Linux Disk Failure Simulation Driver which allows creating an interface that can be configured to generate errors when certain ranges of blocks are read, but it is for the 2.4 Linux Kernel and hasn't been updated for 2.6.
What would be perfect would be an losetup and loop driver that also allowed you to configure it to return read errors when attempting to read from a given set of blocks.
It's not a loopback device you're looking for, but rather device-mapper.
Use dmsetup to create a device backed by the "error" target. It will show up in /dev/mapper/<name>.
Page 7 of the Device mapper presentation (PDF) has exactly what you're looking for:
dmsetup create bad_disk << EOF
0 8 linear /dev/sdb1 0
8 1 error
9 204791 linear /dev/sdb1 9
EOF
Or leave out the sdb1 parts to and put the "error" target as the device for blocks 0 - 8 (instead of sdb1) to make a pure error disk.
See also The Device Mapper appendix from "RHEL 5
Logical Volume Manager Administration".
There's also a flakey target - a combo of linear and error that sometimes succeeds. Also a delay to introduce intentional delays for testing.
It seems like Linux's built-in fault injection capabilities would be a good idea to use.
Blog: http://blog.wpkg.org/2007/11/08/using-fault-injection/
Reference: https://www.kernel.org/doc/Documentation/fault-injection/fault-injection.txt
The easiest way to play with block devices is using nbd.
Download the userland sources from git://github.com/yoe/nbd.git and modify nbd-server.c to fail at reading or writing on whichever areas you want it to fail on, or to fail in a controllably random pattern, or basically anything you want.
I would like to elaborate on Peter Cordes answer.
In bash, setup an image on a loopback device with ext4, then write a file to it named binary.bin.
imageName=faulty.img
mountDir=$(pwd)/mount
sudo umount $mountDir ## make sure nothing is mounted here
dd if=/dev/zero of=$imageName bs=1M count=10
mkfs.ext4 $imageName
loopdev=$(sudo losetup -P -f --show $imageName); echo $loopdev
mkdir $mountDir
sudo mount $loopdev $mountDir
sudo chown -R $USER:$USER mount
echo "2ed99f0039724cd194858869e9debac4" | xxd -r -p > $mountDir/binary.bin
sudo umount $mountDir
in python3 (since bash struggles to deal with binary data) search for the magic binary data in binary.bin
import binascii
with open("faulty.img", "rb") as fd:
s = fd.read()
search = binascii.unhexlify("2ed99f0039724cd194858869e9debac4")
beg=0
find = s.find(search, beg); beg = find+1; print(find)
start_sector = find//512; print(start_sector)
then back in bash mount the faulty block device
start_sector=## copy value from variable start_sector in python
next_sector=$(($start_sector+1))
size=$(($(wc -c $imageName|cut -d ' ' -f1)/512))
len=$(($size-$next_sector))
echo -e "0\t$start_sector\tlinear\t$loopdev\t0" > fault_config
echo -e "$start_sector\t1\terror" >> fault_config
echo -e "$next_sector\t$len\tlinear\t$loopdev\t$next_sector" >> fault_config
cat fault_config | sudo dmsetup create bad_drive
sudo mount /dev/mapper/bad_drive $mountDir
finally we can test the faulty block device by reading a file
cat $mountDir/binary.bin
which produces the error:
cat: /path/to/your/mount/binary.bin: Input/output error
clean up when you're done with testing
sudo umount $mountDir
sudo dmsetup remove bad_drive
sudo losetup -d $loopdev
rm fault_config $imageName

Resources