Disabling Fsync in Laptop_Mode

There are several libraries that help you to disable fsync temporarily so your hard disk doesn't always spin up to save your notebooks battery. Of course that is not very flexible as you need to preload the libraries meaning you have to restart the programs.

One wonders why we have the special laptop_mode if a simple call to fsync can just circumvent it. Tytso already suggested to patch the kernel in his blog as a solution. But he never really looked into it AFAIK. Now I did.

And it really turns out to be much easier than I had thought. The following will show you how to stop your hard disk from spinnig up due to fsync while you're in laptop_mode (echo 5 | sudo tee /proc/sys/vm/laptop_mode). All you need to do is to compile your own kernel with 5 additional lines of code. So get your kernel source ready...

The file to modify is fs/sync.c:
Search for "fsync," and insert at the beginning of the function (after "{"):

SYSCALL_DEFINE1(fsync, unsigned int, fd)
if (unlikely(laptop_mode))
return 0;

That's all you need to add. Now if laptop_mode gets enabled, fsync gets disabled. No need to restart your programs or do anything. And if your system leaves laptop_mode, fsync will come back to life right away.

Be aware that this does *not* disable all and any syncing. Especially the "sync" command in your shell will still work as expected and spin up your hard drive. So "sync" is not a valid test to see if fsync is disabled. But e.g. Chrome is good for testing as it fsyncs every time you close a tab - very bad for disk and battery.

All the hack does is to reroute the fsync call. You probably also want to patch fdatasync. And then you will probably want to disable the printk once you know it's working, otherwise your dmesg will fill up quickly. I bet this has a positive influence on benchmark results by the way (though it's cheating of course).

But in any case:
There's absolutey no warranty. In the opposite: Be warned, playing with laptop_mode and especially with fsync can lead to data loss! This is the consequence of laptop_mode in any case, though. To make sure something is written to disk in laptop_mode you must use "sync" on the command line. This will immediately wake up your HD and write everything in the buffer to disk.

Technical Background Information
I tried "return " before but that somehow leads to tons of requests following. I'm not sure what's better for the application to know what's going on, though. I'm just playing here.
Return 0 tells the application that the call was successful. Of course that's a lie. Instead you could use return -EINVAL. It tells the application that the fsync call is not valid for that file. But the problem is that then it might not call fsync again for the file. Hence it would probably be worse at least if you want to switch on demand between fsync and no fsync for open files.

Actually it's good if the application keeps making fsync calls. That's what we want to. This way we can choose whether to fsync or not depending on the laptop_mode setting.

The unlikely() means that the compiler is told that laptop_mode being active is the exception. This is mean to avoid slowing you down in your normal everyday fsyncing. Of course fsyncing is usually rather expensive anyway so it probably wouldn't make a big difference...

I love it. This is the power of Linux. If I want to try something out, I can just do it myself!
And who knows, maybe this hack will spread and eventually even enter the kernel?

ps. Half way down this post "quotemstr" explains why he thinks this modification is a very bad idea to be in the mainline kernel. Though I think he misses the point that laptop_mode is never active out of the box (e.g. just because you're on a laptop). It isn't. You have to activate it. And it warns you quite clearly that there will be data loss and you can even set how much data loss you are willing to accept. So I think this patch would be worthy of mainline inclusion, as it simply makes laptop_mode behave as expected.

There are more interesting discussions.

You can use ftrace to check out what's using fsync on your system.
trace-cmd record -s 10000 -b 10000 -g '*fsync*' -p function_graph

1 comment:

  1. That could be implemented with LD_PRELOAD.

    That way you don't need to recompile your kernel.


I appreciate comments. And I do read them.