Merge branch 'x86-seccomp-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / fs / btrfs / extent_io.c
index 638e1a5b00e24c0dc6cc85f7e2d014ac93759481..bf3f424e0013c17d3a47047e5c7301abba93bfac 100644 (file)
@@ -2064,7 +2064,7 @@ int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
                return -EROFS;
 
        for (i = 0; i < num_pages; i++) {
-               struct page *p = extent_buffer_page(eb, i);
+               struct page *p = eb->pages[i];
 
                ret = repair_io_failure(root->fs_info->btree_inode, start,
                                        PAGE_CACHE_SIZE, start, p,
@@ -3580,7 +3580,7 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
 
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++) {
-               struct page *p = extent_buffer_page(eb, i);
+               struct page *p = eb->pages[i];
 
                if (!trylock_page(p)) {
                        if (!flush) {
@@ -3601,6 +3601,68 @@ static void end_extent_buffer_writeback(struct extent_buffer *eb)
        wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK);
 }
 
+static void set_btree_ioerr(struct page *page)
+{
+       struct extent_buffer *eb = (struct extent_buffer *)page->private;
+       struct btrfs_inode *btree_ino = BTRFS_I(eb->fs_info->btree_inode);
+
+       SetPageError(page);
+       if (test_and_set_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags))
+               return;
+
+       /*
+        * If writeback for a btree extent that doesn't belong to a log tree
+        * failed, increment the counter transaction->eb_write_errors.
+        * We do this because while the transaction is running and before it's
+        * committing (when we call filemap_fdata[write|wait]_range against
+        * the btree inode), we might have
+        * btree_inode->i_mapping->a_ops->writepages() called by the VM - if it
+        * returns an error or an error happens during writeback, when we're
+        * committing the transaction we wouldn't know about it, since the pages
+        * can be no longer dirty nor marked anymore for writeback (if a
+        * subsequent modification to the extent buffer didn't happen before the
+        * transaction commit), which makes filemap_fdata[write|wait]_range not
+        * able to find the pages tagged with SetPageError at transaction
+        * commit time. So if this happens we must abort the transaction,
+        * otherwise we commit a super block with btree roots that point to
+        * btree nodes/leafs whose content on disk is invalid - either garbage
+        * or the content of some node/leaf from a past generation that got
+        * cowed or deleted and is no longer valid.
+        *
+        * Note: setting AS_EIO/AS_ENOSPC in the btree inode's i_mapping would
+        * not be enough - we need to distinguish between log tree extents vs
+        * non-log tree extents, and the next filemap_fdatawait_range() call
+        * will catch and clear such errors in the mapping - and that call might
+        * be from a log sync and not from a transaction commit. Also, checking
+        * for the eb flag EXTENT_BUFFER_WRITE_ERR at transaction commit time is
+        * not done and would not be reliable - the eb might have been released
+        * from memory and reading it back again means that flag would not be
+        * set (since it's a runtime flag, not persisted on disk).
+        *
+        * Using the flags below in the btree inode also makes us achieve the
+        * goal of AS_EIO/AS_ENOSPC when writepages() returns success, started
+        * writeback for all dirty pages and before filemap_fdatawait_range()
+        * is called, the writeback for all dirty pages had already finished
+        * with errors - because we were not using AS_EIO/AS_ENOSPC,
+        * filemap_fdatawait_range() would return success, as it could not know
+        * that writeback errors happened (the pages were no longer tagged for
+        * writeback).
+        */
+       switch (eb->log_index) {
+       case -1:
+               set_bit(BTRFS_INODE_BTREE_ERR, &btree_ino->runtime_flags);
+               break;
+       case 0:
+               set_bit(BTRFS_INODE_BTREE_LOG1_ERR, &btree_ino->runtime_flags);
+               break;
+       case 1:
+               set_bit(BTRFS_INODE_BTREE_LOG2_ERR, &btree_ino->runtime_flags);
+               break;
+       default:
+               BUG(); /* unexpected, logic error */
+       }
+}
+
 static void end_bio_extent_buffer_writepage(struct bio *bio, int err)
 {
        struct bio_vec *bvec;
@@ -3614,10 +3676,9 @@ static void end_bio_extent_buffer_writepage(struct bio *bio, int err)
                BUG_ON(!eb);
                done = atomic_dec_and_test(&eb->io_pages);
 
-               if (err || test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) {
-                       set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+               if (err || test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) {
                        ClearPageUptodate(page);
-                       SetPageError(page);
+                       set_btree_ioerr(page);
                }
 
                end_page_writeback(page);
@@ -3644,14 +3705,14 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
        int rw = (epd->sync_io ? WRITE_SYNC : WRITE) | REQ_META;
        int ret = 0;
 
-       clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+       clear_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags);
        num_pages = num_extent_pages(eb->start, eb->len);
        atomic_set(&eb->io_pages, num_pages);
        if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID)
                bio_flags = EXTENT_BIO_TREE_LOG;
 
        for (i = 0; i < num_pages; i++) {
-               struct page *p = extent_buffer_page(eb, i);
+               struct page *p = eb->pages[i];
 
                clear_page_dirty_for_io(p);
                set_page_writeback(p);
@@ -3661,8 +3722,8 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
                                         0, epd->bio_flags, bio_flags);
                epd->bio_flags = bio_flags;
                if (ret) {
-                       set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
-                       SetPageError(p);
+                       set_btree_ioerr(p);
+                       end_page_writeback(p);
                        if (atomic_sub_and_test(num_pages - i, &eb->io_pages))
                                end_extent_buffer_writeback(eb);
                        ret = -EIO;
@@ -3675,7 +3736,8 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
 
        if (unlikely(ret)) {
                for (; i < num_pages; i++) {
-                       struct page *p = extent_buffer_page(eb, i);
+                       struct page *p = eb->pages[i];
+                       clear_page_dirty_for_io(p);
                        unlock_page(p);
                }
        }
@@ -4464,7 +4526,7 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb)
 
        do {
                index--;
-               page = extent_buffer_page(eb, index);
+               page = eb->pages[index];
                if (page && mapped) {
                        spin_lock(&page->mapping->private_lock);
                        /*
@@ -4646,7 +4708,8 @@ static void mark_extent_buffer_accessed(struct extent_buffer *eb,
 
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++) {
-               struct page *p = extent_buffer_page(eb, i);
+               struct page *p = eb->pages[i];
+
                if (p != accessed)
                        mark_page_accessed(p);
        }
@@ -4815,7 +4878,7 @@ again:
         */
        SetPageChecked(eb->pages[0]);
        for (i = 1; i < num_pages; i++) {
-               p = extent_buffer_page(eb, i);
+               p = eb->pages[i];
                ClearPageChecked(p);
                unlock_page(p);
        }
@@ -4926,7 +4989,7 @@ void clear_extent_buffer_dirty(struct extent_buffer *eb)
        num_pages = num_extent_pages(eb->start, eb->len);
 
        for (i = 0; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                if (!PageDirty(page))
                        continue;
 
@@ -4962,7 +5025,7 @@ int set_extent_buffer_dirty(struct extent_buffer *eb)
        WARN_ON(!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags));
 
        for (i = 0; i < num_pages; i++)
-               set_page_dirty(extent_buffer_page(eb, i));
+               set_page_dirty(eb->pages[i]);
        return was_dirty;
 }
 
@@ -4975,7 +5038,7 @@ int clear_extent_buffer_uptodate(struct extent_buffer *eb)
        clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                if (page)
                        ClearPageUptodate(page);
        }
@@ -4991,7 +5054,7 @@ int set_extent_buffer_uptodate(struct extent_buffer *eb)
        set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                SetPageUptodate(page);
        }
        return 0;
@@ -5031,7 +5094,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
 
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = start_i; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                if (wait == WAIT_NONE) {
                        if (!trylock_page(page))
                                goto unlock_exit;
@@ -5050,11 +5113,11 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
                goto unlock_exit;
        }
 
-       clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
+       clear_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);
        eb->read_mirror = 0;
        atomic_set(&eb->io_pages, num_reads);
        for (i = start_i; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                if (!PageUptodate(page)) {
                        ClearPageError(page);
                        err = __extent_read_full_page(tree, page,
@@ -5079,7 +5142,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
                return ret;
 
        for (i = start_i; i < num_pages; i++) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                wait_on_page_locked(page);
                if (!PageUptodate(page))
                        ret = -EIO;
@@ -5090,7 +5153,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
 unlock_exit:
        i = start_i;
        while (locked_pages > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                i++;
                unlock_page(page);
                locked_pages--;
@@ -5116,7 +5179,7 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
 
                cur = min(len, (PAGE_CACHE_SIZE - offset));
                kaddr = page_address(page);
@@ -5148,7 +5211,7 @@ int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
 
                cur = min(len, (PAGE_CACHE_SIZE - offset));
                kaddr = page_address(page);
@@ -5197,7 +5260,7 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
                return -EINVAL;
        }
 
-       p = extent_buffer_page(eb, i);
+       p = eb->pages[i];
        kaddr = page_address(p);
        *map = kaddr + offset;
        *map_len = PAGE_CACHE_SIZE - offset;
@@ -5223,7 +5286,7 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
 
                cur = min(len, (PAGE_CACHE_SIZE - offset));
 
@@ -5257,7 +5320,7 @@ void write_extent_buffer(struct extent_buffer *eb, const void *srcv,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                WARN_ON(!PageUptodate(page));
 
                cur = min(len, PAGE_CACHE_SIZE - offset);
@@ -5287,7 +5350,7 @@ void memset_extent_buffer(struct extent_buffer *eb, char c,
        offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(eb, i);
+               page = eb->pages[i];
                WARN_ON(!PageUptodate(page));
 
                cur = min(len, PAGE_CACHE_SIZE - offset);
@@ -5318,7 +5381,7 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
                (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
-               page = extent_buffer_page(dst, i);
+               page = dst->pages[i];
                WARN_ON(!PageUptodate(page));
 
                cur = min(len, (unsigned long)(PAGE_CACHE_SIZE - offset));
@@ -5396,8 +5459,7 @@ void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
                cur = min_t(unsigned long, cur,
                        (unsigned long)(PAGE_CACHE_SIZE - dst_off_in_page));
 
-               copy_pages(extent_buffer_page(dst, dst_i),
-                          extent_buffer_page(dst, src_i),
+               copy_pages(dst->pages[dst_i], dst->pages[src_i],
                           dst_off_in_page, src_off_in_page, cur);
 
                src_offset += cur;
@@ -5443,8 +5505,7 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
 
                cur = min_t(unsigned long, len, src_off_in_page + 1);
                cur = min(cur, dst_off_in_page + 1);
-               copy_pages(extent_buffer_page(dst, dst_i),
-                          extent_buffer_page(dst, src_i),
+               copy_pages(dst->pages[dst_i], dst->pages[src_i],
                           dst_off_in_page - cur + 1,
                           src_off_in_page - cur + 1, cur);