]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/ext4/inode.c
Merge remote-tracking branch 'ext4/dev'
[karo-tx-linux.git] / fs / ext4 / inode.c
index 0d424d7ac02b0a30f98e713bb10403e90ced51b5..05599cd23a1bd7cd054d72cbb8f53163f68ac7d9 100644 (file)
@@ -2178,6 +2178,9 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
  *
  * @handle - handle for journal operations
  * @mpd - extent to map
+ * @give_up_on_write - we set this to true iff there is a fatal error and there
+ *                     is no hope of writing the data. The caller should discard
+ *                     dirty pages to avoid infinite loops.
  *
  * The function maps extent starting at mpd->lblk of length mpd->len. If it is
  * delayed, blocks are allocated, if it is unwritten, we may need to convert
@@ -2295,6 +2298,7 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
        struct address_space *mapping = mpd->inode->i_mapping;
        struct pagevec pvec;
        unsigned int nr_pages;
+       long left = mpd->wbc->nr_to_write;
        pgoff_t index = mpd->first_page;
        pgoff_t end = mpd->last_page;
        int tag;
@@ -2330,6 +2334,17 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
                        if (page->index > end)
                                goto out;
 
+                       /*
+                        * Accumulated enough dirty pages? This doesn't apply
+                        * to WB_SYNC_ALL mode. For integrity sync we have to
+                        * keep going because someone may be concurrently
+                        * dirtying pages, and we might have synced a lot of
+                        * newly appeared dirty pages, but have not synced all
+                        * of the old dirty pages.
+                        */
+                       if (mpd->wbc->sync_mode == WB_SYNC_NONE && left <= 0)
+                               goto out;
+
                        /* If we can't merge this page, we are done. */
                        if (mpd->map.m_len > 0 && mpd->next_page != page->index)
                                goto out;
@@ -2364,19 +2379,7 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
                        if (err <= 0)
                                goto out;
                        err = 0;
-
-                       /*
-                        * Accumulated enough dirty pages? This doesn't apply
-                        * to WB_SYNC_ALL mode. For integrity sync we have to
-                        * keep going because someone may be concurrently
-                        * dirtying pages, and we might have synced a lot of
-                        * newly appeared dirty pages, but have not synced all
-                        * of the old dirty pages.
-                        */
-                       if (mpd->wbc->sync_mode == WB_SYNC_NONE &&
-                           mpd->next_page - mpd->first_page >=
-                                                       mpd->wbc->nr_to_write)
-                               goto out;
+                       left--;
                }
                pagevec_release(&pvec);
                cond_resched();
@@ -2563,7 +2566,7 @@ retry:
                        break;
        }
        blk_finish_plug(&plug);
-       if (!ret && !cycled) {
+       if (!ret && !cycled && wbc->nr_to_write > 0) {
                cycled = 1;
                mpd.last_page = writeback_index - 1;
                mpd.first_page = 0;
@@ -3067,13 +3070,12 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
  *
  */
 static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
-                             const struct iovec *iov, loff_t offset,
-                             unsigned long nr_segs)
+                             struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
        ssize_t ret;
-       size_t count = iov_length(iov, nr_segs);
+       size_t count = iov_iter_count(iter);
        int overwrite = 0;
        get_block_t *get_block_func = NULL;
        int dio_flags = 0;
@@ -3082,7 +3084,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
 
        /* Use the old path for reads and writes beyond i_size. */
        if (rw != WRITE || final_size > inode->i_size)
-               return ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs);
+               return ext4_ind_direct_IO(rw, iocb, iter, offset);
 
        BUG_ON(iocb->private == NULL);
 
@@ -3149,8 +3151,8 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
                dio_flags = DIO_LOCKING;
        }
        ret = __blockdev_direct_IO(rw, iocb, inode,
-                                  inode->i_sb->s_bdev, iov,
-                                  offset, nr_segs,
+                                  inode->i_sb->s_bdev, iter,
+                                  offset,
                                   get_block_func,
                                   ext4_end_io_dio,
                                   NULL,
@@ -3204,8 +3206,7 @@ retake_lock:
 }
 
 static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
-                             const struct iovec *iov, loff_t offset,
-                             unsigned long nr_segs)
+                             struct iov_iter *iter, loff_t offset)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
@@ -3221,13 +3222,12 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
        if (ext4_has_inline_data(inode))
                return 0;
 
-       trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw);
+       trace_ext4_direct_IO_enter(inode, offset, iov_iter_count(iter), rw);
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
-               ret = ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs);
+               ret = ext4_ext_direct_IO(rw, iocb, iter, offset);
        else
-               ret = ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs);
-       trace_ext4_direct_IO_exit(inode, offset,
-                               iov_length(iov, nr_segs), rw, ret);
+               ret = ext4_ind_direct_IO(rw, iocb, iter, offset);
+       trace_ext4_direct_IO_exit(inode, offset, iov_iter_count(iter), rw, ret);
        return ret;
 }