Bug 46981

Summary: [PATCH]/sys/class/*/queue/read_ahead_kb stores unexpected values written by writev
Product: File System Reporter: Dave Reisner (d)
Component: SysFSAssignee: Greg Kroah-Hartman (greg)
Status: RESOLVED CODE_FIX    
Severity: normal CC: alan, florian
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 3.5.3 Subsystem:
Regression: No Bisected commit-id:
Attachments: test program to show behavior
return and check errors from queue_var_store

Description Dave Reisner 2012-09-03 20:01:10 UTC
I've found an inconsistency in the way that some nodes in sysfs handle writes, particularly by writev. I've attached a simple program which illustrates this behavior (I'll call it ./writev from now on).

Running "./writev /sys/kernel/mm/ksm/run 1" yields the expected result -- /sys/kernel/mm/ksm/run will contain "1". I notice, via strace, that the newline appears to be discarded:

# strace -e writev ./writev /sys/kernel/mm/ksm/run 1
writev(3, [{"1", 1}, {"\n", 1}], 2)     = 1

However, running "./writev /sys/class/sda/queue/read_ahead_kb 1024" results in a "0" being stored. This time, strace shows that the entire 5 bytes is written.

# strace -e writev ./writev /sys/class/block/sda/queue/read_ahead_kb 1024
writev(3, [{"1024", 4}, {"\n", 1}], 2)  = 5

Using fprintf, which boils down to a single write syscall, I get the expected behavior in both cases.
Comment 1 Dave Reisner 2012-09-03 20:01:37 UTC
Created attachment 79161 [details]
test program to show behavior
Comment 2 Dave Reisner 2012-09-03 22:41:04 UTC
As I suspected, this is being treated as 2 separate writes. I added a printk to the queue_var_store function in block/blk-sysfs.c, and dmesg now shows the below when I call the equivalent of "./writev /sys/class/block/sda/queue/read_ahead_kb 1024".

[    0.892319] queue_var_store: 1024
[    0.892704] queue_var_store: 0
Comment 3 Dave Reisner 2012-09-04 02:45:25 UTC
And the root of the issue doesn't seem to be the two writes, but the fact that queue_var_store does not seem to not reject invalid values, and the callers of this function never expect it to fail. I would have expected that writing a letter to queue/read_ahead_kb would just return EINVAL, but it instead stores a 0 in the node.

I'm attaching a diff against linus's tree which illustrates this and fixes the immediate issue, but I don't expect this to be a proper/complete fix.
Comment 4 Dave Reisner 2012-09-04 02:45:58 UTC
Created attachment 79171 [details]
return and check errors from queue_var_store
Comment 5 Alan 2012-09-04 10:59:10 UTC
Please send patches, with a Signed-off-by: line to linux-kernel@vger.kernel.org, we can't accept them without the Signed-off-by: line.

thanks
Comment 6 Greg Kroah-Hartman 2012-10-30 16:15:51 UTC
Closing as I don't take patches from bugzilla
Comment 7 Dave Reisner 2012-11-01 14:07:19 UTC
This should have been closed as fixed -- my change was merged via LKML by Jens Axboe:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b1f3b64d76cf88cc
Comment 8 Florian Mickler 2012-11-11 18:58:43 UTC
A patch referencing this bug report has been merged in Linux v3.7-rc1:

commit b1f3b64d76cf88cc250e5cdd1de783ba9737078e
Author: Dave Reisner <dreisner@archlinux.org>
Date:   Sat Sep 8 11:55:45 2012 -0400

    block: reject invalid queue attribute values