Skip to content

Commit d02b047

Browse files
committed
Merge tag 'gfs2-v5.8-rc4.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2
Pull gfs2 fixes from Andreas Gruenbacher: "Fix gfs2 readahead deadlocks by adding a IOCB_NOIO flag that allows gfs2 to use the generic fiel read iterator functions without having to worry about being called back while holding locks". * tag 'gfs2-v5.8-rc4.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: gfs2: Rework read and page fault locking fs: Add IOCB_NOIO flag for generic_file_read_iter
2 parents f4c8824 + 20f8299 commit d02b047

File tree

4 files changed

+73
-48
lines changed

4 files changed

+73
-48
lines changed

fs/gfs2/aops.c

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -468,21 +468,10 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
468468
}
469469

470470

471-
/**
472-
* __gfs2_readpage - readpage
473-
* @file: The file to read a page for
474-
* @page: The page to read
475-
*
476-
* This is the core of gfs2's readpage. It's used by the internal file
477-
* reading code as in that case we already hold the glock. Also it's
478-
* called by gfs2_readpage() once the required lock has been granted.
479-
*/
480-
481471
static int __gfs2_readpage(void *file, struct page *page)
482472
{
483473
struct gfs2_inode *ip = GFS2_I(page->mapping->host);
484474
struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
485-
486475
int error;
487476

488477
if (i_blocksize(page->mapping->host) == PAGE_SIZE &&
@@ -505,36 +494,11 @@ static int __gfs2_readpage(void *file, struct page *page)
505494
* gfs2_readpage - read a page of a file
506495
* @file: The file to read
507496
* @page: The page of the file
508-
*
509-
* This deals with the locking required. We have to unlock and
510-
* relock the page in order to get the locking in the right
511-
* order.
512497
*/
513498

514499
static int gfs2_readpage(struct file *file, struct page *page)
515500
{
516-
struct address_space *mapping = page->mapping;
517-
struct gfs2_inode *ip = GFS2_I(mapping->host);
518-
struct gfs2_holder gh;
519-
int error;
520-
521-
unlock_page(page);
522-
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
523-
error = gfs2_glock_nq(&gh);
524-
if (unlikely(error))
525-
goto out;
526-
error = AOP_TRUNCATED_PAGE;
527-
lock_page(page);
528-
if (page->mapping == mapping && !PageUptodate(page))
529-
error = __gfs2_readpage(file, page);
530-
else
531-
unlock_page(page);
532-
gfs2_glock_dq(&gh);
533-
out:
534-
gfs2_holder_uninit(&gh);
535-
if (error && error != AOP_TRUNCATED_PAGE)
536-
lock_page(page);
537-
return error;
501+
return __gfs2_readpage(file, page);
538502
}
539503

540504
/**
@@ -598,16 +562,9 @@ static void gfs2_readahead(struct readahead_control *rac)
598562
{
599563
struct inode *inode = rac->mapping->host;
600564
struct gfs2_inode *ip = GFS2_I(inode);
601-
struct gfs2_holder gh;
602565

603-
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
604-
if (gfs2_glock_nq(&gh))
605-
goto out_uninit;
606566
if (!gfs2_is_stuffed(ip))
607567
mpage_readahead(rac, gfs2_block_map);
608-
gfs2_glock_dq(&gh);
609-
out_uninit:
610-
gfs2_holder_uninit(&gh);
611568
}
612569

613570
/**

fs/gfs2/file.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,8 +558,29 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
558558
return block_page_mkwrite_return(ret);
559559
}
560560

561+
static vm_fault_t gfs2_fault(struct vm_fault *vmf)
562+
{
563+
struct inode *inode = file_inode(vmf->vma->vm_file);
564+
struct gfs2_inode *ip = GFS2_I(inode);
565+
struct gfs2_holder gh;
566+
vm_fault_t ret;
567+
int err;
568+
569+
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
570+
err = gfs2_glock_nq(&gh);
571+
if (err) {
572+
ret = block_page_mkwrite_return(err);
573+
goto out_uninit;
574+
}
575+
ret = filemap_fault(vmf);
576+
gfs2_glock_dq(&gh);
577+
out_uninit:
578+
gfs2_holder_uninit(&gh);
579+
return ret;
580+
}
581+
561582
static const struct vm_operations_struct gfs2_vm_ops = {
562-
.fault = filemap_fault,
583+
.fault = gfs2_fault,
563584
.map_pages = filemap_map_pages,
564585
.page_mkwrite = gfs2_page_mkwrite,
565586
};
@@ -824,6 +845,9 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
824845

825846
static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
826847
{
848+
struct gfs2_inode *ip;
849+
struct gfs2_holder gh;
850+
size_t written = 0;
827851
ssize_t ret;
828852

829853
if (iocb->ki_flags & IOCB_DIRECT) {
@@ -832,7 +856,31 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
832856
return ret;
833857
iocb->ki_flags &= ~IOCB_DIRECT;
834858
}
835-
return generic_file_read_iter(iocb, to);
859+
iocb->ki_flags |= IOCB_NOIO;
860+
ret = generic_file_read_iter(iocb, to);
861+
iocb->ki_flags &= ~IOCB_NOIO;
862+
if (ret >= 0) {
863+
if (!iov_iter_count(to))
864+
return ret;
865+
written = ret;
866+
} else {
867+
if (ret != -EAGAIN)
868+
return ret;
869+
if (iocb->ki_flags & IOCB_NOWAIT)
870+
return ret;
871+
}
872+
ip = GFS2_I(iocb->ki_filp->f_mapping->host);
873+
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
874+
ret = gfs2_glock_nq(&gh);
875+
if (ret)
876+
goto out_uninit;
877+
ret = generic_file_read_iter(iocb, to);
878+
if (ret > 0)
879+
written += ret;
880+
gfs2_glock_dq(&gh);
881+
out_uninit:
882+
gfs2_holder_uninit(&gh);
883+
return written ? written : ret;
836884
}
837885

838886
/**

include/linux/fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ enum rw_hint {
315315
#define IOCB_SYNC (1 << 5)
316316
#define IOCB_WRITE (1 << 6)
317317
#define IOCB_NOWAIT (1 << 7)
318+
#define IOCB_NOIO (1 << 9)
318319

319320
struct kiocb {
320321
struct file *ki_filp;

mm/filemap.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,7 +2028,7 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb,
20282028

20292029
page = find_get_page(mapping, index);
20302030
if (!page) {
2031-
if (iocb->ki_flags & IOCB_NOWAIT)
2031+
if (iocb->ki_flags & (IOCB_NOWAIT | IOCB_NOIO))
20322032
goto would_block;
20332033
page_cache_sync_readahead(mapping,
20342034
ra, filp,
@@ -2038,6 +2038,10 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb,
20382038
goto no_cached_page;
20392039
}
20402040
if (PageReadahead(page)) {
2041+
if (iocb->ki_flags & IOCB_NOIO) {
2042+
put_page(page);
2043+
goto out;
2044+
}
20412045
page_cache_async_readahead(mapping,
20422046
ra, filp, page,
20432047
index, last_index - index);
@@ -2160,6 +2164,11 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb,
21602164
}
21612165

21622166
readpage:
2167+
if (iocb->ki_flags & IOCB_NOIO) {
2168+
unlock_page(page);
2169+
put_page(page);
2170+
goto would_block;
2171+
}
21632172
/*
21642173
* A previous I/O error may have been due to temporary
21652174
* failures, eg. multipath errors.
@@ -2249,9 +2258,19 @@ EXPORT_SYMBOL_GPL(generic_file_buffered_read);
22492258
*
22502259
* This is the "read_iter()" routine for all filesystems
22512260
* that can use the page cache directly.
2261+
*
2262+
* The IOCB_NOWAIT flag in iocb->ki_flags indicates that -EAGAIN shall
2263+
* be returned when no data can be read without waiting for I/O requests
2264+
* to complete; it doesn't prevent readahead.
2265+
*
2266+
* The IOCB_NOIO flag in iocb->ki_flags indicates that no new I/O
2267+
* requests shall be made for the read or for readahead. When no data
2268+
* can be read, -EAGAIN shall be returned. When readahead would be
2269+
* triggered, a partial, possibly empty read shall be returned.
2270+
*
22522271
* Return:
22532272
* * number of bytes copied, even for partial reads
2254-
* * negative error code if nothing was read
2273+
* * negative error code (or 0 if IOCB_NOIO) if nothing was read
22552274
*/
22562275
ssize_t
22572276
generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)

0 commit comments

Comments
 (0)