barrier: Don't return -EOPNOTSUPP to the caller if the device does not support barriers barrier
authorJens Axboe <jens.axboe@oracle.com>
Tue, 31 Mar 2009 17:00:53 +0000 (19:00 +0200)
committerJens Axboe <jens.axboe@oracle.com>
Tue, 31 Mar 2009 17:00:53 +0000 (19:00 +0200)
The caller cannot really do much about the situation anyway. Instead log
a warning if this is the first such failed barrier we see, so that the
admin can look into whether this poses a data integrity problem or not.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
14 files changed:
block/blk-barrier.c
block/blk-settings.c
block/ioctl.c
fs/bio.c
fs/btrfs/disk-io.c
fs/btrfs/extent_io.c
fs/buffer.c
fs/fat/misc.c
fs/gfs2/log.c
fs/jbd2/commit.c
fs/reiserfs/journal.c
fs/xfs/linux-2.6/xfs_aops.c
include/linux/blkdev.h
include/linux/buffer_head.h

index f7dae57e6cabdcfaaed15762c4d2b7b9889e6c77..8660146f8c75e0869528e58361d383f84723a5ff 100644 (file)
@@ -338,9 +338,7 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector)
                *error_sector = bio->bi_sector;
 
        ret = 0;
-       if (bio_flagged(bio, BIO_EOPNOTSUPP))
-               ret = -EOPNOTSUPP;
-       else if (!bio_flagged(bio, BIO_UPTODATE))
+       if (!bio_flagged(bio, BIO_UPTODATE))
                ret = -EIO;
 
        bio_put(bio);
@@ -408,9 +406,7 @@ int blkdev_issue_discard(struct block_device *bdev,
                submit_bio(DISCARD_BARRIER, bio);
 
                /* Check if it failed immediately */
-               if (bio_flagged(bio, BIO_EOPNOTSUPP))
-                       ret = -EOPNOTSUPP;
-               else if (!bio_flagged(bio, BIO_UPTODATE))
+               if (!bio_flagged(bio, BIO_UPTODATE))
                        ret = -EIO;
                bio_put(bio);
        }
index 59fd05d9f1d5d8022d1b16a5263d6ae087aadb21..0a81466fe8950e85419901ecde560b9d4c62fe99 100644 (file)
@@ -463,6 +463,19 @@ void blk_queue_update_dma_alignment(struct request_queue *q, int mask)
 }
 EXPORT_SYMBOL(blk_queue_update_dma_alignment);
 
+void blk_queue_set_noflush(struct block_device *bdev)
+{
+       struct request_queue *q = bdev_get_queue(bdev);
+       char b[BDEVNAME_SIZE];
+
+       if (test_and_set_bit(QUEUE_FLAG_NOFLUSH, &q->queue_flags))
+               return;
+
+       printk(KERN_ERR "Device %s does not appear to honor cache flushes. "    
+                       "This may mean that file system ordering guarantees "
+                       "are not met.", bdevname(bdev, b));
+}
+
 static int __init blk_settings_init(void)
 {
        blk_max_low_pfn = max_low_pfn - 1;
index 0f22e629b13c8e93bf46401c0913605b5d2cbfba..769f7be13d7907dec1b06a6c18ec58fe5f2f9ad0 100644 (file)
@@ -166,9 +166,7 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
 
                wait_for_completion(&wait);
 
-               if (bio_flagged(bio, BIO_EOPNOTSUPP))
-                       ret = -EOPNOTSUPP;
-               else if (!bio_flagged(bio, BIO_UPTODATE))
+               if (!bio_flagged(bio, BIO_UPTODATE))
                        ret = -EIO;
                bio_put(bio);
        }
index a040cde7f6fd567f68a7c28504f9f25d6a274146..79e3cec86a9e9a7aca8f4f2f9086f5488627babc 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1380,7 +1380,17 @@ void bio_check_pages_dirty(struct bio *bio)
  **/
 void bio_endio(struct bio *bio, int error)
 {
-       if (error)
+       /*
+        * Special case here - hide the -EOPNOTSUPP from the driver or
+        * block layer, dump a warning the first time this happens so that
+        * the admin knows that we may not provide the ordering guarantees
+        * that are needed. Don't clear the uptodate bit.
+        */
+       if (error == -EOPNOTSUPP && bio_barrier(bio)) {
+               set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
+               blk_queue_set_noflush(bio->bi_bdev);
+               error = 0;
+       } else if (error)
                clear_bit(BIO_UPTODATE, &bio->bi_flags);
        else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
                error = -EIO;
index 6ec80c0fc8697a0a9171e72a8dd4e63905c7993e..fd3ea97ac729024367261f63fbd1a54f6b24ea9d 100644 (file)
@@ -1951,11 +1951,6 @@ static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate)
        if (uptodate) {
                set_buffer_uptodate(bh);
        } else {
-               if (!buffer_eopnotsupp(bh) && printk_ratelimit()) {
-                       printk(KERN_WARNING "lost page write due to "
-                                       "I/O error on %s\n",
-                                      bdevname(bh->b_bdev, b));
-               }
                /* note, we dont' set_buffer_write_io_error because we have
                 * our own ways of dealing with the IO errors
                 */
index ebe6b29e60698156250708766c70bb74b903bfb6..d696d26e1788a56e345dc138c60dd6af1aa7d93d 100644 (file)
@@ -1834,7 +1834,6 @@ extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
 static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
                          unsigned long bio_flags)
 {
-       int ret = 0;
        struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
        struct page *page = bvec->bv_page;
        struct extent_io_tree *tree = bio->bi_private;
@@ -1846,17 +1845,13 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
 
        bio->bi_private = NULL;
 
-       bio_get(bio);
-
        if (tree->ops && tree->ops->submit_bio_hook)
                tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
                                           mirror_num, bio_flags);
        else
                submit_bio(rw, bio);
-       if (bio_flagged(bio, BIO_EOPNOTSUPP))
-               ret = -EOPNOTSUPP;
-       bio_put(bio);
-       return ret;
+
+       return 0;
 }
 
 static int submit_extent_page(int rw, struct extent_io_tree *tree,
index a2fd743d97cb85380b5140e5d84ba9c50c383b84..6f50e08653f79d36d1ab4835e8658131976a9151 100644 (file)
@@ -147,17 +147,9 @@ void end_buffer_read_sync(struct buffer_head *bh, int uptodate)
 
 void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
 {
-       char b[BDEVNAME_SIZE];
-
        if (uptodate) {
                set_buffer_uptodate(bh);
        } else {
-               if (!buffer_eopnotsupp(bh) && !quiet_error(bh)) {
-                       buffer_io_error(bh);
-                       printk(KERN_WARNING "lost page write due to "
-                                       "I/O error on %s\n",
-                                      bdevname(bh->b_bdev, b));
-               }
                set_buffer_write_io_error(bh);
                clear_buffer_uptodate(bh);
        }
@@ -2828,7 +2820,7 @@ static void end_bio_bh_io_sync(struct bio *bio, int err)
 
        if (err == -EOPNOTSUPP) {
                set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
-               set_bit(BH_Eopnotsupp, &bh->b_state);
+               err = 0;
        }
 
        if (unlikely (test_bit(BIO_QUIET,&bio->bi_flags)))
@@ -2841,7 +2833,6 @@ static void end_bio_bh_io_sync(struct bio *bio, int err)
 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));
@@ -2879,14 +2870,8 @@ int submit_bh(int rw, struct buffer_head * 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;
+       return 0;
 }
 
 /**
@@ -2965,10 +2950,6 @@ int sync_dirty_buffer(struct buffer_head *bh)
                bh->b_end_io = end_buffer_write_sync;
                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 {
index ac39ebcc149676b9eb35c15c8ddcff722f43a69f..406da54a6809dcdfe14e9eded0d027152d25a79d 100644 (file)
@@ -269,10 +269,7 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
        ll_rw_block(SWRITE, nr_bhs, bhs);
        for (i = 0; i < nr_bhs; i++) {
                wait_on_buffer(bhs[i]);
-               if (buffer_eopnotsupp(bhs[i])) {
-                       clear_buffer_eopnotsupp(bhs[i]);
-                       err = -EOPNOTSUPP;
-               } else if (!err && !buffer_uptodate(bhs[i]))
+               if (!err && !buffer_uptodate(bhs[i]))
                        err = -EIO;
        }
        return err;
index 98918a756410ca576f3fec0ba49fa8a82869033f..78c3d596c622dc8b2037e78e17d707205c136157 100644 (file)
@@ -578,6 +578,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
        struct gfs2_log_header *lh;
        unsigned int tail;
        u32 hash;
+       int rw;
 
        bh = sb_getblk(sdp->sd_vfs, blkno);
        lock_buffer(bh);
@@ -602,20 +603,13 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
 
        bh->b_end_io = end_buffer_write_sync;
        if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags))
-               goto skip_barrier;
+               rw = WRITE;
+       else
+               rw = WRITE_BARRIER;
+
        get_bh(bh);
-       submit_bh(WRITE_BARRIER | (1 << BIO_RW_META), bh);
+       submit_bh(rw | (1 << BIO_RW_META), bh);
        wait_on_buffer(bh);
-       if (buffer_eopnotsupp(bh)) {
-               clear_buffer_eopnotsupp(bh);
-               set_buffer_uptodate(bh);
-               set_bit(SDF_NOBARRIERS, &sdp->sd_flags);
-               lock_buffer(bh);
-skip_barrier:
-               get_bh(bh);
-               submit_bh(WRITE_SYNC | (1 << BIO_RW_META), bh);
-               wait_on_buffer(bh);
-       }
        if (!buffer_uptodate(bh))
                gfs2_io_error_bh(sdp, bh);
        brelse(bh);
index 62804e57a44caf2f893d16cc481f7ac347efe19a..c1de70c4a1598c6e2d1a21a76c65b17fc43ee43a 100644 (file)
@@ -174,30 +174,8 @@ static int journal_wait_on_commit_record(journal_t *journal,
 {
        int ret = 0;
 
-retry:
        clear_buffer_dirty(bh);
        wait_on_buffer(bh);
-       if (buffer_eopnotsupp(bh) && (journal->j_flags & JBD2_BARRIER)) {
-               printk(KERN_WARNING
-                      "JBD2: wait_on_commit_record: sync failed on %s - "
-                      "disabling barriers\n", journal->j_devname);
-               spin_lock(&journal->j_state_lock);
-               journal->j_flags &= ~JBD2_BARRIER;
-               spin_unlock(&journal->j_state_lock);
-
-               lock_buffer(bh);
-               clear_buffer_dirty(bh);
-               set_buffer_uptodate(bh);
-               bh->b_end_io = journal_end_buffer_io_sync;
-
-               ret = submit_bh(WRITE_SYNC, bh);
-               if (ret) {
-                       unlock_buffer(bh);
-                       return ret;
-               }
-               goto retry;
-       }
-
        if (unlikely(!buffer_uptodate(bh)))
                ret = -EIO;
        put_bh(bh);            /* One for getblk() */
index 77f5bb746bf073969140539752ee87dc8f4f0861..5eefa6c3ec7031cf3bc2600a103dbcb1ad8e7bf9 100644 (file)
@@ -700,18 +700,6 @@ static int submit_barrier_buffer(struct buffer_head *bh)
        return submit_bh(WRITE_BARRIER, bh);
 }
 
-static void check_barrier_completion(struct super_block *s,
-                                    struct buffer_head *bh)
-{
-       if (buffer_eopnotsupp(bh)) {
-               clear_buffer_eopnotsupp(bh);
-               disable_barrier(s);
-               set_buffer_uptodate(bh);
-               set_buffer_dirty(bh);
-               sync_dirty_buffer(bh);
-       }
-}
-
 #define CHUNK_SIZE 32
 struct buffer_chunk {
        struct buffer_head *bh[CHUNK_SIZE];
@@ -1148,8 +1136,6 @@ static int flush_commit_list(struct super_block *s,
        } else
                wait_on_buffer(jl->j_commit_bh);
 
-       check_barrier_completion(s, jl->j_commit_bh);
-
        /* If there was a write error in the journal - we can't commit this
         * transaction - it will be invalid and, if successful, will just end
         * up propagating the write error out to the filesystem. */
@@ -1313,7 +1299,6 @@ static int _update_journal_header_block(struct super_block *sb,
                                goto sync;
                        }
                        wait_on_buffer(journal->j_header_bh);
-                       check_barrier_completion(sb, journal->j_header_bh);
                } else {
                      sync:
                        set_buffer_dirty(journal->j_header_bh);
index de3a198f771e20627769b837d6f2460ec18077fc..c0cacb27843632ba81f40a17f84f8d19d418cdea 100644 (file)
@@ -406,7 +406,6 @@ xfs_submit_ioend_bio(
        bio->bi_end_io = xfs_end_bio;
 
        submit_bio(WRITE, bio);
-       ASSERT(!bio_flagged(bio, BIO_EOPNOTSUPP));
        bio_put(bio);
 }
 
index 465d6babc847a2603d4f23a5e842cd7dc07b308e..ea2e15af8ca926cc223c1eada19ab5a2e60d5f22 100644 (file)
@@ -452,6 +452,7 @@ struct request_queue
 #define QUEUE_FLAG_NONROT      14      /* non-rotational device (SSD) */
 #define QUEUE_FLAG_VIRT        QUEUE_FLAG_NONROT /* paravirt device */
 #define QUEUE_FLAG_IO_STAT     15      /* do IO stats */
+#define QUEUE_FLAG_NOFLUSH     16      /* device doesn't do flushes */
 
 #define QUEUE_FLAG_DEFAULT     ((1 << QUEUE_FLAG_IO_STAT) |            \
                                 (1 << QUEUE_FLAG_CLUSTER) |            \
@@ -789,6 +790,7 @@ extern int blk_execute_rq(struct request_queue *, struct gendisk *,
 extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
                                  struct request *, int, rq_end_io_fn *);
 extern void blk_unplug(struct request_queue *q);
+extern void blk_queue_set_noflush(struct block_device *bdev);
 
 static inline struct request_queue *bdev_get_queue(struct block_device *bdev)
 {
index f19fd9045ea0a621e05bc6eb11d515a78656f8bb..8adcaa4223438c0b3b8e40f7864fdd335e453374 100644 (file)
@@ -33,7 +33,6 @@ enum bh_state_bits {
        BH_Boundary,    /* Block is followed by a discontiguity */
        BH_Write_EIO,   /* I/O error on write */
        BH_Ordered,     /* ordered write */
-       BH_Eopnotsupp,  /* operation not supported (barrier) */
        BH_Unwritten,   /* Buffer is allocated on disk but not written */
        BH_Quiet,       /* Buffer Error Prinks to be quiet */
 
@@ -126,7 +125,6 @@ BUFFER_FNS(Delay, delay)
 BUFFER_FNS(Boundary, boundary)
 BUFFER_FNS(Write_EIO, write_io_error)
 BUFFER_FNS(Ordered, ordered)
-BUFFER_FNS(Eopnotsupp, eopnotsupp)
 BUFFER_FNS(Unwritten, unwritten)
 
 #define bh_offset(bh)          ((unsigned long)(bh)->b_data & ~PAGE_MASK)