diff options
-rw-r--r-- | include/linux/fs.h | 2 | ||||
-rw-r--r-- | mm/filemap.c | 37 |
2 files changed, 23 insertions, 16 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h index 9dfd7c7ff8e3..87be51aff9d7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -48,6 +48,7 @@ struct cred; | |||
48 | struct swap_info_struct; | 48 | struct swap_info_struct; |
49 | struct seq_file; | 49 | struct seq_file; |
50 | struct workqueue_struct; | 50 | struct workqueue_struct; |
51 | struct iov_iter; | ||
51 | 52 | ||
52 | extern void __init inode_init(void); | 53 | extern void __init inode_init(void); |
53 | extern void __init inode_init_early(void); | 54 | extern void __init inode_init_early(void); |
@@ -2396,6 +2397,7 @@ extern ssize_t __generic_file_aio_write(struct kiocb *, const struct iovec *, un | |||
2396 | extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); | 2397 | extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); |
2397 | extern ssize_t generic_file_direct_write(struct kiocb *, const struct iovec *, | 2398 | extern ssize_t generic_file_direct_write(struct kiocb *, const struct iovec *, |
2398 | unsigned long *, loff_t, size_t, size_t); | 2399 | unsigned long *, loff_t, size_t, size_t); |
2400 | extern ssize_t generic_perform_write(struct file *, struct iov_iter *, loff_t); | ||
2399 | extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *, | 2401 | extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *, |
2400 | unsigned long, loff_t, size_t, ssize_t); | 2402 | unsigned long, loff_t, size_t, ssize_t); |
2401 | extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); | 2403 | extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); |
diff --git a/mm/filemap.c b/mm/filemap.c index 93e9cf576452..09bfc9b3bb51 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2092,7 +2092,7 @@ found: | |||
2092 | } | 2092 | } |
2093 | EXPORT_SYMBOL(grab_cache_page_write_begin); | 2093 | EXPORT_SYMBOL(grab_cache_page_write_begin); |
2094 | 2094 | ||
2095 | static ssize_t generic_perform_write(struct file *file, | 2095 | ssize_t generic_perform_write(struct file *file, |
2096 | struct iov_iter *i, loff_t pos) | 2096 | struct iov_iter *i, loff_t pos) |
2097 | { | 2097 | { |
2098 | struct address_space *mapping = file->f_mapping; | 2098 | struct address_space *mapping = file->f_mapping; |
@@ -2180,6 +2180,7 @@ again: | |||
2180 | 2180 | ||
2181 | return written ? written : status; | 2181 | return written ? written : status; |
2182 | } | 2182 | } |
2183 | EXPORT_SYMBOL(generic_perform_write); | ||
2183 | 2184 | ||
2184 | ssize_t | 2185 | ssize_t |
2185 | generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, | 2186 | generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, |
@@ -2230,8 +2231,10 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
2230 | size_t count; /* after file limit checks */ | 2231 | size_t count; /* after file limit checks */ |
2231 | struct inode *inode = mapping->host; | 2232 | struct inode *inode = mapping->host; |
2232 | loff_t pos = iocb->ki_pos; | 2233 | loff_t pos = iocb->ki_pos; |
2233 | ssize_t written; | 2234 | ssize_t written = 0; |
2234 | ssize_t err; | 2235 | ssize_t err; |
2236 | ssize_t status; | ||
2237 | struct iov_iter from; | ||
2235 | 2238 | ||
2236 | ocount = 0; | 2239 | ocount = 0; |
2237 | err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); | 2240 | err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); |
@@ -2242,8 +2245,6 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
2242 | 2245 | ||
2243 | /* We can write back this queue in page reclaim */ | 2246 | /* We can write back this queue in page reclaim */ |
2244 | current->backing_dev_info = mapping->backing_dev_info; | 2247 | current->backing_dev_info = mapping->backing_dev_info; |
2245 | written = 0; | ||
2246 | |||
2247 | err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); | 2248 | err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); |
2248 | if (err) | 2249 | if (err) |
2249 | goto out; | 2250 | goto out; |
@@ -2259,44 +2260,47 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
2259 | if (err) | 2260 | if (err) |
2260 | goto out; | 2261 | goto out; |
2261 | 2262 | ||
2263 | iov_iter_init(&from, iov, nr_segs, count, 0); | ||
2264 | |||
2262 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ | 2265 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ |
2263 | if (unlikely(file->f_flags & O_DIRECT)) { | 2266 | if (unlikely(file->f_flags & O_DIRECT)) { |
2264 | loff_t endbyte; | 2267 | loff_t endbyte; |
2265 | ssize_t written_buffered; | ||
2266 | 2268 | ||
2267 | written = generic_file_direct_write(iocb, iov, &nr_segs, pos, | 2269 | written = generic_file_direct_write(iocb, iov, &from.nr_segs, pos, |
2268 | count, ocount); | 2270 | count, ocount); |
2269 | if (written < 0 || written == count) | 2271 | if (written < 0 || written == count) |
2270 | goto out; | 2272 | goto out; |
2273 | iov_iter_advance(&from, written); | ||
2274 | |||
2271 | /* | 2275 | /* |
2272 | * direct-io write to a hole: fall through to buffered I/O | 2276 | * direct-io write to a hole: fall through to buffered I/O |
2273 | * for completing the rest of the request. | 2277 | * for completing the rest of the request. |
2274 | */ | 2278 | */ |
2275 | pos += written; | 2279 | pos += written; |
2276 | count -= written; | 2280 | count -= written; |
2277 | written_buffered = generic_file_buffered_write(iocb, iov, | 2281 | |
2278 | nr_segs, pos, count, written); | 2282 | status = generic_perform_write(file, &from, pos); |
2279 | /* | 2283 | /* |
2280 | * If generic_file_buffered_write() retuned a synchronous error | 2284 | * If generic_perform_write() returned a synchronous error |
2281 | * then we want to return the number of bytes which were | 2285 | * then we want to return the number of bytes which were |
2282 | * direct-written, or the error code if that was zero. Note | 2286 | * direct-written, or the error code if that was zero. Note |
2283 | * that this differs from normal direct-io semantics, which | 2287 | * that this differs from normal direct-io semantics, which |
2284 | * will return -EFOO even if some bytes were written. | 2288 | * will return -EFOO even if some bytes were written. |
2285 | */ | 2289 | */ |
2286 | if (written_buffered < 0) { | 2290 | if (unlikely(status < 0) && !written) { |
2287 | err = written_buffered; | 2291 | err = status; |
2288 | goto out; | 2292 | goto out; |
2289 | } | 2293 | } |
2290 | 2294 | iocb->ki_pos = pos + status; | |
2291 | /* | 2295 | /* |
2292 | * We need to ensure that the page cache pages are written to | 2296 | * We need to ensure that the page cache pages are written to |
2293 | * disk and invalidated to preserve the expected O_DIRECT | 2297 | * disk and invalidated to preserve the expected O_DIRECT |
2294 | * semantics. | 2298 | * semantics. |
2295 | */ | 2299 | */ |
2296 | endbyte = pos + written_buffered - written - 1; | 2300 | endbyte = pos + status - 1; |
2297 | err = filemap_write_and_wait_range(file->f_mapping, pos, endbyte); | 2301 | err = filemap_write_and_wait_range(file->f_mapping, pos, endbyte); |
2298 | if (err == 0) { | 2302 | if (err == 0) { |
2299 | written = written_buffered; | 2303 | written += status; |
2300 | invalidate_mapping_pages(mapping, | 2304 | invalidate_mapping_pages(mapping, |
2301 | pos >> PAGE_CACHE_SHIFT, | 2305 | pos >> PAGE_CACHE_SHIFT, |
2302 | endbyte >> PAGE_CACHE_SHIFT); | 2306 | endbyte >> PAGE_CACHE_SHIFT); |
@@ -2307,8 +2311,9 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
2307 | */ | 2311 | */ |
2308 | } | 2312 | } |
2309 | } else { | 2313 | } else { |
2310 | written = generic_file_buffered_write(iocb, iov, nr_segs, | 2314 | written = generic_perform_write(file, &from, pos); |
2311 | pos, count, written); | 2315 | if (likely(written >= 0)) |
2316 | iocb->ki_pos = pos + written; | ||
2312 | } | 2317 | } |
2313 | out: | 2318 | out: |
2314 | current->backing_dev_info = NULL; | 2319 | current->backing_dev_info = NULL; |