bio->bi_iter.bi_size += len;
bio->bi_vcnt++;
-
- if (!bio_flagged(bio, BIO_WORKINGSET) && unlikely(PageWorkingset(page)))
- bio_set_flag(bio, BIO_WORKINGSET);
}
EXPORT_SYMBOL_GPL(__bio_add_page);
* fit into the bio, or are requested in @iter, whatever is smaller. If
* MM encounters an error pinning the requested pages, it stops. Error
* is returned only if 0 pages could be pinned.
- *
- * It's intended for direct IO, so doesn't do PSI tracking, the caller is
- * responsible for setting BIO_WORKINGSET if necessary.
*/
int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
{
ret = __bio_iov_iter_get_pages(bio, iter);
} while (!ret && iov_iter_count(iter) && !bio_full(bio, 0));
- /* don't account direct I/O as memory stall */
- bio_clear_flag(bio, BIO_WORKINGSET);
return bio->bi_vcnt ? 0 : ret;
}
EXPORT_SYMBOL_GPL(bio_iov_iter_get_pages);
#include <linux/t10-pi.h>
#include <linux/debugfs.h>
#include <linux/bpf.h>
-#include <linux/psi.h>
#include <linux/part_stat.h>
#include <linux/sched/sysctl.h>
#include <linux/blk-crypto.h>
}
}
- /*
- * If we're reading data that is part of the userspace workingset, count
- * submission time as memory stall. When the device is congested, or
- * the submitting cgroup IO-throttled, submission can be a significant
- * part of overall IO time.
- */
- if (unlikely(bio_op(bio) == REQ_OP_READ &&
- bio_flagged(bio, BIO_WORKINGSET))) {
- unsigned long pflags;
-
- psi_memstall_enter(&pflags);
- submit_bio_noacct(bio);
- psi_memstall_leave(&pflags);
- return;
- }
-
submit_bio_noacct(bio);
}
EXPORT_SYMBOL(submit_bio);
unsigned long flags;
bio->bi_private = dio;
- /* don't account direct I/O as memory stall */
- bio_clear_flag(bio, BIO_WORKINGSET);
spin_lock_irqsave(&dio->bio_lock, flags);
dio->refcount++;
BIO_NO_PAGE_REF, /* don't put release vec pages */
BIO_CLONED, /* doesn't own data */
BIO_BOUNCED, /* bio is a bounce bio */
- BIO_WORKINGSET, /* contains userspace workingset pages */
BIO_QUIET, /* Make BIO Quiet */
BIO_CHAIN, /* chained bio, ->bi_remaining in effect */
BIO_REFFED, /* bio has elevated ->bi_cnt */
static int filemap_read_folio(struct file *file, struct address_space *mapping,
struct folio *folio)
{
+ bool workingset = folio_test_workingset(folio);
+ unsigned long pflags;
int error;
/*
* fails.
*/
folio_clear_error(folio);
+
/* Start the actual read. The read will unlock the page. */
+ if (unlikely(workingset))
+ psi_memstall_enter(&pflags);
error = mapping->a_ops->readpage(file, &folio->page);
+ if (unlikely(workingset))
+ psi_memstall_leave(&pflags);
if (error)
return error;
static struct folio *do_read_cache_folio(struct address_space *mapping,
pgoff_t index, filler_t filler, void *data, gfp_t gfp)
{
+ unsigned long pflags;
struct folio *folio;
+ bool workingset;
int err;
repeat:
}
}
+ workingset = folio_test_workingset(folio);
+ if (unlikely(workingset))
+ psi_memstall_enter(&pflags);
if (filler)
err = filler(data, &folio->page);
else
err = mapping->a_ops->readpage(data, &folio->page);
+ if (unlikely(workingset))
+ psi_memstall_leave(&pflags);
if (err < 0) {
folio_put(folio);
return ERR_PTR(err);
#include <linux/task_io_accounting_ops.h>
#include <linux/pagevec.h>
#include <linux/pagemap.h>
+#include <linux/psi.h>
#include <linux/syscalls.h>
#include <linux/file.h>
#include <linux/mm_inline.h>
}
EXPORT_SYMBOL_GPL(file_ra_state_init);
-static void read_pages(struct readahead_control *rac)
+static void read_pages(struct readahead_control *rac, bool workingset)
{
const struct address_space_operations *aops = rac->mapping->a_ops;
struct page *page;
struct blk_plug plug;
+ unsigned long pflags;
if (!readahead_count(rac))
return;
+ if (unlikely(workingset))
+ psi_memstall_enter(&pflags);
blk_start_plug(&plug);
-
if (aops->readahead) {
aops->readahead(rac);
/*
put_page(page);
}
}
-
blk_finish_plug(&plug);
+ if (unlikely(workingset))
+ psi_memstall_leave(&pflags);
BUG_ON(readahead_count(rac));
}
struct address_space *mapping = ractl->mapping;
unsigned long index = readahead_index(ractl);
gfp_t gfp_mask = readahead_gfp_mask(mapping);
+ bool workingset = false;
unsigned long i;
/*
* have a stable reference to this page, and it's
* not worth getting one just for that.
*/
- read_pages(ractl);
+ read_pages(ractl, workingset);
ractl->_index++;
i = ractl->_index + ractl->_nr_pages - index - 1;
+ workingset = false;
continue;
}
if (filemap_add_folio(mapping, folio, index + i,
gfp_mask) < 0) {
folio_put(folio);
- read_pages(ractl);
+ read_pages(ractl, workingset);
ractl->_index++;
i = ractl->_index + ractl->_nr_pages - index - 1;
+ workingset = false;
continue;
}
if (i == nr_to_read - lookahead_size)
folio_set_readahead(folio);
ractl->_nr_pages++;
+ workingset |= folio_test_workingset(folio);
}
/*
* uptodate then the caller will launch readpage again, and
* will then handle the error.
*/
- read_pages(ractl);
+ read_pages(ractl, workingset);
filemap_invalidate_unlock_shared(mapping);
memalloc_nofs_restore(nofs);
}
pgoff_t index = readahead_index(ractl);
pgoff_t limit = (i_size_read(mapping->host) - 1) >> PAGE_SHIFT;
pgoff_t mark = index + ra->size - ra->async_size;
+ bool workingset = false;
int err = 0;
gfp_t gfp = readahead_gfp_mask(mapping);
break;
}
+ workingset |= folio_test_workingset(folio);
ractl->_nr_pages += 1UL << order;
index += 1UL << order;
}
ra->async_size += index - limit - 1;
}
- read_pages(ractl);
+ read_pages(ractl, workingset);
/*
* If there were already pages in the page cache, then we may have