Reading page from given block device
Hi!
For swsusp, I kind of need to read 4K from given block device.
Here's my attempt:
static int bdev_read_page(kdev_t dev, long pos, void *buf)
{
struct buffer_head *bh;
struct block_device *bdev;
if (pos%PAGE_SIZE) panic("Sorry, dave, I can't let you do
that!\n");
bdev = bdget(kdev_t_to_nr(dev));
if (!bdev) {
printk("No block device for %s\n", __bdevname(dev));
BUG();
}
printk("C");
bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE);
printk("D");
bdput(bdev);
if (!bh || (!bh->b_data)) {
return -1;
}
memcpy(buf, bh->b_data, PAGE_SIZE);
bforget(bh); /* FIXME: maybe bforget should
be here */
return 0;
}It works *once*, second time it deadlocks in __bread(). I tried both bforget() and brelse(). Kernel is 2.5.13. What am I doing wrong/what's wrong?
Pavel
Signature · 2 lines
(about SSSCA) "I don't say this lightly. However, I really think that the U.S. no longer is classifiable as a democracy, but rather as a plutocracy." --hpa
Quoted 7 lines · Pavel Machek
Hi!
For swsusp, I kind of need to read 4K from given block device.
Here's my attempt:
Quoted 7 lines
static int
bdev_read_page(kdev_t dev, long pos, void *buf){ struct buffer_head *bh; struct block_device *bdev; if (pos%PAGE_SIZE) panic("Sorry, dave, I can't let you dothat!\n");
It's possible I guess that someone has a pinned buffer against the same page which has a different block size. See the "lock up" comment over __getblk().
Quoted 5 lines
bdev = bdget(kdev_t_to_nr(dev));
if (!bdev) {
printk("No block device for %s\n", __bdevname(dev));
BUG();
}Quoted 8 lines
printk("C");
bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE);
printk("D");
bdput(bdev);
if (!bh || (!bh->b_data)) {
return -1;
}
memcpy(buf, bh->b_data, PAGE_SIZE);You'll need to kmap bh->b_page before copying the data.
Quoted 4 lines
It works *once*, second time it deadlocks in
__bread(). I tried bothbforget()andbrelse(). Kernel is 2.5.13. What am I doing wrong/what's wrong?
brelse is safer.
Please try 2.5.14. 2.5.13 had a few leaky problems which could perhaps result in a pinned buffer which will cause try_to_free_buffers() to fail, which triggers the __getblk() nastiness.
Generally, if you're reading from a swap partition then it may be better to use brw_page(). bread() is backed by bdev->bd_inode->i_mapping, and there may be coherency problems if the target blocks are currently in swapper_space. Although probably your bdget() here will create a new inode with no pagecache, so it'll work OK.
It really depends on what you're trying to do. It may be best to just cook up a local buffer_head and submit the darn thing.
-
Quoted 5 lines · Andrew Morton
..
Quoted 1 line
memcpy(buf, bh->b_data, PAGE_SIZE);You'll need to kmap
bh->b_pagebefore copying the data.
No you won't. blockdev mappings don't use highmem.
-
Hi!
Quoted 9 lines
Quoted 9 lines
For swsusp, I kind of need to read 4K from given block device.
Here's my attempt:
static int
bdev_read_page(kdev_t dev, long pos, void *buf){ struct buffer_head *bh; struct block_device *bdev;
Quoted 6 lines
Quoted 2 lines
if (pos%PAGE_SIZE) panic("Sorry, dave, I can't let you do
that!\n");It's possible I guess that someone has a pinned buffer against the same page which has a different block size. See the "lock up" comment over
__getblk().
Well, I'm doing it during boot, and this is swap partition; it should not have been accessed previously.
Quoted 14 lines
Quoted 5 lines
bdev = bdget(kdev_t_to_nr(dev)); if (!bdev) { printk("No block device for %s\n", __bdevname(dev)); BUG(); }Quoted 8 lines
printk("C"); bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE); printk("D"); bdput(bdev); if (!bh || (!bh->b_data)) { return -1; } memcpy(buf, bh->b_data, PAGE_SIZE);
Quoted 1 line
You'll need to kmap
bh->b_pagebefore copying the data.
This machine does not have himem.
Quoted 6 lines
Quoted 3 lines
It works *once*, second time it deadlocks in
__bread(). I tried bothbforget()andbrelse(). Kernel is 2.5.13. What am I doing wrong/what's wrong?brelse is safer.
Quoted 7 lines
Please try 2.5.14. 2.5.13 had a few leaky problems which could perhaps result in a pinned buffer which will cause
try_to_free_buffers()to fail, which triggers the__getblk()nastiness.Generally, if you're reading from a swap partition then it may be better to use
brw_page().bread()is backed
It is swap partition, but system does not yet know its swap at that point. This is next boot, that partition was not yet accessed.
Pavel
Signature · 2 lines
Casualities in World Trade Center: ~3k dead inside the building, cryptography in U.S.A. and free speech in Czech Republic.
Quoted 9 lines · Pavel Machek
Well, I'm doing it during boot, and this is swap partition; it should not have been accessed previously.
Quoted 6 lines
Quoted 6 lines
bdev = bdget(kdev_t_to_nr(dev)); if (!bdev) { printk("No block device for %s\n", __bdevname(dev)); BUG(); } printk("C");
blkdev_open(bdev, FMODE_READ, O_RDONLY, BDEV_RAW)
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE); printk("D"); bdput(bdev);
nope - blkdev_put(bdev), and do it _after_ you are done with buffers. Oh, and you need to do brelse().
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
if (!bh || (!bh->b_data)) { return -1;
However, I would really suggest to open the bugger once, do all IO and then close it. See how raw.c and friends deal with these problems.
Hi!
Quoted 11 lines
Quoted 9 lines
Well, I'm doing it during boot, and this is swap partition; it should not have been accessed previously.
Quoted 6 lines
Quoted 6 lines
bdev = bdget(kdev_t_to_nr(dev)); if (!bdev) { printk("No block device for %s\n", __bdevname(dev)); BUG(); } printk("C");
blkdev_open(bdev, FMODE_READ, O_RDONLY, BDEV_RAW)
blkdev_open is
fs.h:extern int blkdev_open(struct inode *, struct file *);
... I can't see how to use it in this context.
Quoted 5 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
if (!bh || (!bh->b_data)) { return -1;However, I would really suggest to open the bugger once, do all IO and then close it. See how
raw.cand friends deal with these problems.
Performance should not matter here.
Pavel
Signature · 2 lines
Casualities in World Trade Center: ~3k dead inside the building, cryptography in U.S.A. and free speech in Czech Republic.
Quoted 12 lines · Pavel Machek
Hi!
Quoted 10 lines
Quoted 9 lines
Well, I'm doing it during boot, and this is swap partition; it should not have been accessed previously.
Quoted 6 lines
Quoted 6 lines
bdev = bdget(kdev_t_to_nr(dev)); if (!bdev) { printk("No block device for %s\n", __bdevname(dev)); BUG(); } printk("C");
Quoted 3 lines
Quoted 1 line
blkdev_open(bdev, FMODE_READ, O_RDONLY, BDEV_RAW)
blkdev_openis
grr... s/open/get/ - sorry.
Quoted 11 lines
fs.h:extern int
blkdev_open(struct inode *, struct file *);... I can't see how to use it in this context.
Quoted 5 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
if (!bh || (!bh->b_data)) { return -1;However, I would really suggest to open the bugger once, do all IO and then close it. See how
raw.cand friends deal with these problems.Performance should not matter here.
Yeah, but amount of places that mess with kdev_t should.
Hi!
Quoted 39 lines
Quoted 6 lines
Hi!
For swsusp, I kind of need to read 4K from given block device.
Here's my attempt:
Quoted 7 lines
static int
bdev_read_page(kdev_t dev, long pos, void *buf){ struct buffer_head *bh; struct block_device *bdev; if (pos%PAGE_SIZE) panic("Sorry, dave, I can't let you dothat!\n");
It's possible I guess that someone has a pinned buffer against the same page which has a different block size. See the "lock up" comment over
__getblk().Quoted 5 lines
bdev = bdget(kdev_t_to_nr(dev)); if (!bdev) { printk("No block device for %s\n", __bdevname(dev)); BUG(); }Quoted 8 lines
printk("C"); bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE); printk("D"); bdput(bdev); if (!bh || (!bh->b_data)) { return -1; } memcpy(buf, bh->b_data, PAGE_SIZE);You'll need to kmap
bh->b_pagebefore copying the data.Quoted 4 lines
It works *once*, second time it deadlocks in
__bread(). I tried bothbforget()andbrelse(). Kernel is 2.5.13. What am I doing wrong/what's wrong?
Quoted 6 lines
brelse is safer.
Please try 2.5.14. 2.5.13 had a few leaky problems which could perhaps result in a pinned buffer which will cause
try_to_free_buffers()to fail, which triggers the__getblk()nastiness.
Went with brelse(), and switched to 2.5.14; still deadlocks on second read.
Pavel
Signature · 2 lines
Casualities in World Trade Center: ~3k dead inside the building, cryptography in U.S.A. and free speech in Czech Republic.
Hi!
Quoted 6 lines
Quoted 3 lines
It is swap partition, but system does not yet know its swap at that point. This is next boot, that partition was not yet accessed.
PavelIn that case, I don't know. Sorry. sysrq-T is your friend (and kgdb is your god). Let me know...
Call trace is
c01229ed -- bdev_read_pagec0134b5b -- __bread
That's stable (as expected). Under that, it was seen in
c0134a57 -- __getblk
blk_get_queue
ata_get_queue
Second try:
c0134a28 -- __getblk
__get_hash_table
Third try:
c0134a28 -- __getblkc01343cc -- __get_hash_table
Fourth try:
c0134abd -- __getblk
... I should get some sleep I guess...
Pavel
Signature · 2 lines
Casualities in World Trade Center: ~3k dead inside the building, cryptography in U.S.A. and free speech in Czech Republic.
Quoted 6 lines · Pavel Machek
...
Second try:
c0134a28--__getblk
__get_hash_table
hmm. It looks like your blockdev may have the wrong blocksize in bd_inode->i_blkbits, and __get_hash_table cannot find the 4k block against the 1k blocksize device. It keeps returning zero.
The new pagecache-based __get_hash_table uses bd_inode->i_blkbits to go from a block number to a pagecache index. That works fine when called via the official `bread()' function, but probably your __bread() approach has confused it.
Try running set_blocksize(bdev, PAGE_SIZE) before calling __bread().
-