|
@@ -252,6 +252,88 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(iomap_file_buffered_write);
|
|
|
|
|
|
+static struct page *
|
|
|
+__iomap_read_page(struct inode *inode, loff_t offset)
|
|
|
+{
|
|
|
+ struct address_space *mapping = inode->i_mapping;
|
|
|
+ struct page *page;
|
|
|
+
|
|
|
+ page = read_mapping_page(mapping, offset >> PAGE_SHIFT, NULL);
|
|
|
+ if (IS_ERR(page))
|
|
|
+ return page;
|
|
|
+ if (!PageUptodate(page)) {
|
|
|
+ put_page(page);
|
|
|
+ return ERR_PTR(-EIO);
|
|
|
+ }
|
|
|
+ return page;
|
|
|
+}
|
|
|
+
|
|
|
+static loff_t
|
|
|
+iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
|
|
|
+ struct iomap *iomap)
|
|
|
+{
|
|
|
+ long status = 0;
|
|
|
+ ssize_t written = 0;
|
|
|
+
|
|
|
+ do {
|
|
|
+ struct page *page, *rpage;
|
|
|
+ unsigned long offset; /* Offset into pagecache page */
|
|
|
+ unsigned long bytes; /* Bytes to write to page */
|
|
|
+
|
|
|
+ offset = (pos & (PAGE_SIZE - 1));
|
|
|
+ bytes = min_t(unsigned long, PAGE_SIZE - offset, length);
|
|
|
+
|
|
|
+ rpage = __iomap_read_page(inode, pos);
|
|
|
+ if (IS_ERR(rpage))
|
|
|
+ return PTR_ERR(rpage);
|
|
|
+
|
|
|
+ status = iomap_write_begin(inode, pos, bytes,
|
|
|
+ AOP_FLAG_NOFS | AOP_FLAG_UNINTERRUPTIBLE,
|
|
|
+ &page, iomap);
|
|
|
+ put_page(rpage);
|
|
|
+ if (unlikely(status))
|
|
|
+ return status;
|
|
|
+
|
|
|
+ WARN_ON_ONCE(!PageUptodate(page));
|
|
|
+
|
|
|
+ status = iomap_write_end(inode, pos, bytes, bytes, page);
|
|
|
+ if (unlikely(status <= 0)) {
|
|
|
+ if (WARN_ON_ONCE(status == 0))
|
|
|
+ return -EIO;
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ cond_resched();
|
|
|
+
|
|
|
+ pos += status;
|
|
|
+ written += status;
|
|
|
+ length -= status;
|
|
|
+
|
|
|
+ balance_dirty_pages_ratelimited(inode->i_mapping);
|
|
|
+ } while (length);
|
|
|
+
|
|
|
+ return written;
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len,
|
|
|
+ struct iomap_ops *ops)
|
|
|
+{
|
|
|
+ loff_t ret;
|
|
|
+
|
|
|
+ while (len) {
|
|
|
+ ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, NULL,
|
|
|
+ iomap_dirty_actor);
|
|
|
+ if (ret <= 0)
|
|
|
+ return ret;
|
|
|
+ pos += ret;
|
|
|
+ len -= ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(iomap_file_dirty);
|
|
|
+
|
|
|
static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset,
|
|
|
unsigned bytes, struct iomap *iomap)
|
|
|
{
|