[PATCH] fix multiple mark_page_accessed called when sequentially writing a file with blocksize less than PAGE_SIZE ,which might pollute the LRU.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



sequential write to a file with blocksize less than PAGE_SIZE  will call
mark_page_accessed multiple times,

	if (!pagevec_space(pvec))
 		__pagevec_lru_add(pvec, lru);
it seems this trick fix this problem,but not quite thoroughly. there's a chance
that when another page was added to the pvec before the 14th page was
secondly mark_page_accesseded, then the 14th page was still active.



diff --git a/fs/open.c b/fs/open.c
index 9b33c0c..a418419 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -674,6 +674,13 @@ int open_check_o_direct(struct file *f)
 	return 0;
 }

+
+static void
+file_w_state_init(struct file_w_state *wstat)
+{
+	wstat->prev_w_pos=-1;
+}
+
 static int do_dentry_open(struct file *f,
 			  int (*open)(struct inode *, struct file *),
 			  const struct cred *cred)
@@ -730,6 +737,7 @@ static int do_dentry_open(struct file *f,
 	f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

 	file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
+	file_w_state_init(&f->f_wstat);

 	return 0;

diff --git a/include/linux/fs.h b/include/linux/fs.h
index 7617ee0..b90d3ff 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -746,6 +746,10 @@ struct file_ra_state {
 	loff_t prev_pos;		/* Cache last read() position */
 };

+struct file_w_state {
+	loff_t prev_w_pos;
+};
+
 /*
  * Check if @index falls in the readahead windows.
  */
@@ -787,6 +791,7 @@ struct file {
 	struct fown_struct	f_owner;
 	const struct cred	*f_cred;
 	struct file_ra_state	f_ra;
+	struct file_w_state		f_wstat;

 	u64			f_version;
 #ifdef CONFIG_SECURITY
diff --git a/mm/filemap.c b/mm/filemap.c
index 83efee7..ea144a9 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2287,6 +2287,9 @@ static ssize_t generic_perform_write(struct file *file,
 	long status = 0;
 	ssize_t written = 0;
 	unsigned int flags = 0;
+	unsigned long prev_pos=file->f_wstat.prev_w_pos;
+	unsigned long prev_off=(prev_pos & (PAGE_CACHE_SIZE -1));
+	pgoff_t prev_index=(prev_pos >> PAGE_CACHE_SHIFT);

 	/*
 	 * Copies from kernel address space cannot fail (NFSD is a big user).
@@ -2296,12 +2299,14 @@ static ssize_t generic_perform_write(struct file *file,

 	do {
 		struct page *page;
+		pgoff_t index;
 		unsigned long offset;	/* Offset into pagecache page */
 		unsigned long bytes;	/* Bytes to write to page */
 		size_t copied;		/* Bytes copied from user */
 		void *fsdata;

 		offset = (pos & (PAGE_CACHE_SIZE - 1));
+		index = pos >> PAGE_CACHE_SHIFT;
 		bytes = min_t(unsigned long, PAGE_CACHE_SIZE - offset,
 						iov_iter_count(i));

@@ -2334,7 +2339,8 @@ again:
 		pagefault_enable();
 		flush_dcache_page(page);

-		mark_page_accessed(page);
+		if (index != prev_index || offset != prev_off)
+			mark_page_accessed(page);
 		status = a_ops->write_end(file, mapping, pos, bytes, copied,
 						page, fsdata);
 		if (unlikely(status < 0))
@@ -2359,6 +2365,8 @@ again:
 		}
 		pos += copied;
 		written += copied;
+		prev_index = index;
+		prev_off = offset;

 		balance_dirty_pages_ratelimited(mapping);
 		if (fatal_signal_pending(current)) {
@@ -2367,6 +2375,7 @@ again:
 		}
 	} while (iov_iter_count(i));

+	file->f_wstat.prev_w_pos=pos;
 	return written ? written : status;
 }
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux