#include <linux/cpu.h>
#include <asm/bitops.h>
+static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
static void invalidate_bh_lrus(void);
#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
if (uptodate) {
set_buffer_uptodate(bh);
} else {
- if (printk_ratelimit()) {
+ if (!buffer_eopnotsupp(bh) && printk_ratelimit()) {
buffer_io_error(bh);
printk(KERN_WARNING "lost page write due to "
"I/O error on %s\n",
* PageLocked prevents anyone from starting writeback of a page which is
* under read I/O (PageWriteback is only ever set against a locked page).
*/
-void mark_buffer_async_read(struct buffer_head *bh)
+static void mark_buffer_async_read(struct buffer_head *bh)
{
bh->b_end_io = end_buffer_async_read;
set_buffer_async_read(bh);
}
-EXPORT_SYMBOL(mark_buffer_async_read);
void mark_buffer_async_write(struct buffer_head *bh)
{
* b_inode back.
*/
-void buffer_insert_list(spinlock_t *lock,
- struct buffer_head *bh, struct list_head *list)
-{
- spin_lock(lock);
- list_move_tail(&bh->b_assoc_buffers, list);
- spin_unlock(lock);
-}
-
/*
* The buffer's backing address_space's private_lock must be held
*/
if (mapping->assoc_mapping != buffer_mapping)
BUG();
}
- if (list_empty(&bh->b_assoc_buffers))
- buffer_insert_list(&buffer_mapping->private_lock,
- bh, &mapping->private_list);
+ if (list_empty(&bh->b_assoc_buffers)) {
+ spin_lock(&buffer_mapping->private_lock);
+ list_move_tail(&bh->b_assoc_buffers,
+ &mapping->private_list);
+ spin_unlock(&buffer_mapping->private_lock);
+ }
}
EXPORT_SYMBOL(mark_buffer_dirty_inode);
* the osync code to catch these locked, dirty buffers without requeuing
* any newly dirty buffers for write.
*/
-int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
+static int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
{
struct buffer_head *bh;
struct list_head tmp;
{
struct buffer_head *bh = __find_get_block(bdev, block, size);
+ might_sleep();
if (bh == NULL)
bh = __getblk_slow(bdev, block, size);
return bh;
{
struct buffer_head *old_bh;
+ might_sleep();
+
old_bh = __find_get_block_slow(bdev, block, 0);
if (old_bh) {
clear_buffer_dirty(old_bh);
if (bio->bi_size)
return 1;
+ if (err == -EOPNOTSUPP) {
+ set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
+ set_bit(BH_Eopnotsupp, &bh->b_state);
+ }
+
bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags));
bio_put(bio);
return 0;
}
-void submit_bh(int rw, struct buffer_head * bh)
+int submit_bh(int rw, struct buffer_head * bh)
{
struct bio *bio;
+ int ret = 0;
BUG_ON(!buffer_locked(bh));
BUG_ON(!buffer_mapped(bh));
BUG_ON(!bh->b_end_io);
- /* Only clear out a write error when rewriting */
- if (test_set_buffer_req(bh) && rw == WRITE)
+ if (buffer_ordered(bh) && (rw == WRITE))
+ rw = WRITE_BARRIER;
+
+ /*
+ * Only clear out a write error when rewriting, should this
+ * include WRITE_SYNC as well?
+ */
+ if (test_set_buffer_req(bh) && (rw == WRITE || rw == WRITE_BARRIER))
clear_buffer_write_io_error(bh);
/*
bio->bi_end_io = end_bio_bh_io_sync;
bio->bi_private = bh;
+ bio_get(bio);
submit_bio(rw, bio);
+
+ if (bio_flagged(bio, BIO_EOPNOTSUPP))
+ ret = -EOPNOTSUPP;
+
+ bio_put(bio);
+ return ret;
}
/**
/*
* For a data-integrity writeout, we need to wait upon any in-progress I/O
- * and then start new I/O and then wait upon it.
+ * and then start new I/O and then wait upon it. The caller must have a ref on
+ * the buffer_head.
*/
-void sync_dirty_buffer(struct buffer_head *bh)
+int sync_dirty_buffer(struct buffer_head *bh)
{
+ int ret = 0;
+
WARN_ON(atomic_read(&bh->b_count) < 1);
lock_buffer(bh);
if (test_clear_buffer_dirty(bh)) {
get_bh(bh);
bh->b_end_io = end_buffer_write_sync;
- submit_bh(WRITE, bh);
+ ret = submit_bh(WRITE, bh);
wait_on_buffer(bh);
+ if (buffer_eopnotsupp(bh)) {
+ clear_buffer_eopnotsupp(bh);
+ ret = -EOPNOTSUPP;
+ }
+ if (!ret && !buffer_uptodate(bh))
+ ret = -EIO;
} else {
unlock_buffer(bh);
}
+ return ret;
}
/*
EXPORT_SYMBOL(block_sync_page);
EXPORT_SYMBOL(block_truncate_page);
EXPORT_SYMBOL(block_write_full_page);
-EXPORT_SYMBOL(buffer_insert_list);
EXPORT_SYMBOL(cont_prepare_write);
EXPORT_SYMBOL(end_buffer_async_write);
EXPORT_SYMBOL(end_buffer_read_sync);
EXPORT_SYMBOL(end_buffer_write_sync);
EXPORT_SYMBOL(file_fsync);
EXPORT_SYMBOL(fsync_bdev);
-EXPORT_SYMBOL(fsync_buffers_list);
EXPORT_SYMBOL(generic_block_bmap);
EXPORT_SYMBOL(generic_commit_write);
EXPORT_SYMBOL(generic_cont_expand);