|
@@ -1895,22 +1895,9 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
|
|
}
|
|
}
|
|
|
|
|
|
status = a_ops->prepare_write(file, page, offset, offset+bytes);
|
|
status = a_ops->prepare_write(file, page, offset, offset+bytes);
|
|
- if (unlikely(status)) {
|
|
|
|
- loff_t isize = i_size_read(inode);
|
|
|
|
|
|
+ if (unlikely(status))
|
|
|
|
+ goto fs_write_aop_error;
|
|
|
|
|
|
- if (status != AOP_TRUNCATED_PAGE)
|
|
|
|
- unlock_page(page);
|
|
|
|
- page_cache_release(page);
|
|
|
|
- if (status == AOP_TRUNCATED_PAGE)
|
|
|
|
- continue;
|
|
|
|
- /*
|
|
|
|
- * prepare_write() may have instantiated a few blocks
|
|
|
|
- * outside i_size. Trim these off again.
|
|
|
|
- */
|
|
|
|
- if (pos + bytes > isize)
|
|
|
|
- vmtruncate(inode, isize);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
if (likely(nr_segs == 1))
|
|
if (likely(nr_segs == 1))
|
|
copied = filemap_copy_from_user(page, offset,
|
|
copied = filemap_copy_from_user(page, offset,
|
|
buf, bytes);
|
|
buf, bytes);
|
|
@@ -1919,40 +1906,53 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
|
|
cur_iov, iov_offset, bytes);
|
|
cur_iov, iov_offset, bytes);
|
|
flush_dcache_page(page);
|
|
flush_dcache_page(page);
|
|
status = a_ops->commit_write(file, page, offset, offset+bytes);
|
|
status = a_ops->commit_write(file, page, offset, offset+bytes);
|
|
- if (status == AOP_TRUNCATED_PAGE) {
|
|
|
|
- page_cache_release(page);
|
|
|
|
- continue;
|
|
|
|
|
|
+ if (unlikely(status < 0 || status == AOP_TRUNCATED_PAGE))
|
|
|
|
+ goto fs_write_aop_error;
|
|
|
|
+ if (unlikely(copied != bytes)) {
|
|
|
|
+ status = -EFAULT;
|
|
|
|
+ goto fs_write_aop_error;
|
|
}
|
|
}
|
|
|
|
+ if (unlikely(status > 0)) /* filesystem did partial write */
|
|
|
|
+ copied = status;
|
|
|
|
+
|
|
if (likely(copied > 0)) {
|
|
if (likely(copied > 0)) {
|
|
- if (!status)
|
|
|
|
- status = copied;
|
|
|
|
-
|
|
|
|
- if (status >= 0) {
|
|
|
|
- written += status;
|
|
|
|
- count -= status;
|
|
|
|
- pos += status;
|
|
|
|
- buf += status;
|
|
|
|
- if (unlikely(nr_segs > 1)) {
|
|
|
|
- filemap_set_next_iovec(&cur_iov,
|
|
|
|
- &iov_offset, status);
|
|
|
|
- if (count)
|
|
|
|
- buf = cur_iov->iov_base +
|
|
|
|
- iov_offset;
|
|
|
|
- } else {
|
|
|
|
- iov_offset += status;
|
|
|
|
- }
|
|
|
|
|
|
+ written += copied;
|
|
|
|
+ count -= copied;
|
|
|
|
+ pos += copied;
|
|
|
|
+ buf += copied;
|
|
|
|
+ if (unlikely(nr_segs > 1)) {
|
|
|
|
+ filemap_set_next_iovec(&cur_iov,
|
|
|
|
+ &iov_offset, copied);
|
|
|
|
+ if (count)
|
|
|
|
+ buf = cur_iov->iov_base + iov_offset;
|
|
|
|
+ } else {
|
|
|
|
+ iov_offset += copied;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- if (unlikely(copied != bytes))
|
|
|
|
- if (status >= 0)
|
|
|
|
- status = -EFAULT;
|
|
|
|
unlock_page(page);
|
|
unlock_page(page);
|
|
mark_page_accessed(page);
|
|
mark_page_accessed(page);
|
|
page_cache_release(page);
|
|
page_cache_release(page);
|
|
- if (status < 0)
|
|
|
|
- break;
|
|
|
|
balance_dirty_pages_ratelimited(mapping);
|
|
balance_dirty_pages_ratelimited(mapping);
|
|
cond_resched();
|
|
cond_resched();
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+fs_write_aop_error:
|
|
|
|
+ if (status != AOP_TRUNCATED_PAGE)
|
|
|
|
+ unlock_page(page);
|
|
|
|
+ page_cache_release(page);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * prepare_write() may have instantiated a few blocks
|
|
|
|
+ * outside i_size. Trim these off again. Don't need
|
|
|
|
+ * i_size_read because we hold i_mutex.
|
|
|
|
+ */
|
|
|
|
+ if (pos + bytes > inode->i_size)
|
|
|
|
+ vmtruncate(inode, inode->i_size);
|
|
|
|
+ if (status == AOP_TRUNCATED_PAGE)
|
|
|
|
+ continue;
|
|
|
|
+ else
|
|
|
|
+ break;
|
|
|
|
+
|
|
} while (count);
|
|
} while (count);
|
|
*ppos = pos;
|
|
*ppos = pos;
|
|
|
|
|