@@ -2092,7 +2092,7 @@ struct page *grab_cache_page_write_begin(struct address_space *mapping,
20922092}
20932093EXPORT_SYMBOL (grab_cache_page_write_begin );
20942094
2095- static ssize_t generic_perform_write (struct file * file ,
2095+ ssize_t generic_perform_write (struct file * file ,
20962096 struct iov_iter * i , loff_t pos )
20972097{
20982098 struct address_space * mapping = file -> f_mapping ;
@@ -2180,6 +2180,7 @@ static ssize_t generic_perform_write(struct file *file,
21802180
21812181 return written ? written : status ;
21822182}
2183+ EXPORT_SYMBOL (generic_perform_write );
21832184
21842185ssize_t
21852186generic_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,
22302231 size_t count ; /* after file limit checks */
22312232 struct inode * inode = mapping -> host ;
22322233 loff_t pos = iocb -> ki_pos ;
2233- ssize_t written ;
2234+ ssize_t written = 0 ;
22342235 ssize_t err ;
2236+ ssize_t status ;
2237+ struct iov_iter from ;
22352238
22362239 ocount = 0 ;
22372240 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,
22422245
22432246 /* We can write back this queue in page reclaim */
22442247 current -> backing_dev_info = mapping -> backing_dev_info ;
2245- written = 0 ;
2246-
22472248 err = generic_write_checks (file , & pos , & count , S_ISBLK (inode -> i_mode ));
22482249 if (err )
22492250 goto out ;
@@ -2259,44 +2260,47 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
22592260 if (err )
22602261 goto out ;
22612262
2263+ iov_iter_init (& from , iov , nr_segs , count , 0 );
2264+
22622265 /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
22632266 if (unlikely (file -> f_flags & O_DIRECT )) {
22642267 loff_t endbyte ;
2265- ssize_t written_buffered ;
22662268
2267- written = generic_file_direct_write (iocb , iov , & nr_segs , pos ,
2269+ written = generic_file_direct_write (iocb , iov , & from . nr_segs , pos ,
22682270 count , ocount );
22692271 if (written < 0 || written == count )
22702272 goto out ;
2273+ iov_iter_advance (& from , written );
2274+
22712275 /*
22722276 * direct-io write to a hole: fall through to buffered I/O
22732277 * for completing the rest of the request.
22742278 */
22752279 pos += written ;
22762280 count -= written ;
2277- written_buffered = generic_file_buffered_write ( iocb , iov ,
2278- nr_segs , pos , count , written );
2281+
2282+ status = generic_perform_write ( file , & from , pos );
22792283 /*
2280- * If generic_file_buffered_write () retuned a synchronous error
2284+ * If generic_perform_write () returned a synchronous error
22812285 * then we want to return the number of bytes which were
22822286 * direct-written, or the error code if that was zero. Note
22832287 * that this differs from normal direct-io semantics, which
22842288 * will return -EFOO even if some bytes were written.
22852289 */
2286- if (written_buffered < 0 ) {
2287- err = written_buffered ;
2290+ if (unlikely ( status < 0 ) && ! written ) {
2291+ err = status ;
22882292 goto out ;
22892293 }
2290-
2294+ iocb -> ki_pos = pos + status ;
22912295 /*
22922296 * We need to ensure that the page cache pages are written to
22932297 * disk and invalidated to preserve the expected O_DIRECT
22942298 * semantics.
22952299 */
2296- endbyte = pos + written_buffered - written - 1 ;
2300+ endbyte = pos + status - 1 ;
22972301 err = filemap_write_and_wait_range (file -> f_mapping , pos , endbyte );
22982302 if (err == 0 ) {
2299- written = written_buffered ;
2303+ written += status ;
23002304 invalidate_mapping_pages (mapping ,
23012305 pos >> PAGE_CACHE_SHIFT ,
23022306 endbyte >> PAGE_CACHE_SHIFT );
@@ -2307,8 +2311,9 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
23072311 */
23082312 }
23092313 } else {
2310- written = generic_file_buffered_write (iocb , iov , nr_segs ,
2311- pos , count , written );
2314+ written = generic_perform_write (file , & from , pos );
2315+ if (likely (written >= 0 ))
2316+ iocb -> ki_pos = pos + written ;
23122317 }
23132318out :
23142319 current -> backing_dev_info = NULL ;
0 commit comments