Skip to contentSkip to conversation

Rework mtime and ctime updates on mmaped

PATCH Superseded Andy Lutomirski 3 participants 26 messages Aug 16, 2013 – Aug 21, 2013

Subsystems (7)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v3 cover Rework mtime and ctime updates on mmaped

Writes via mmap currently update mtime and ctime in ->page_mkwrite. This hurts both throughput and latency. In workloads that dirty a large number of mmapped pages, ->page_mkwrite can be hot and file_update_time is slow and scales poorly. Updating timestamps can also sleep, which hurts latency for real-time workloads.

This is also a correctness issue. SuS says:

The st_ctime and st_mtime fields of a file that is mapped with MAP_SHARED and PROT_WRITE, will be marked for update at some point in the interval between a write reference to the mapped region and the next call to msync() with MS_ASYNC or MS_SYNC for that portion of the file by any process. If there is no such call, these fields may be marked for update at any time after a write reference if the underlying file is modified as a result.

Currently, if the same mmapped page is written twice, the timestamp may not be update at all after the second write, whereas SuS (and anything using timestamps to invalidate caches, backup data, etc.) would expect the timestamp to eventually be updated.

This patchset attempts to fix both issues at once. It adds a new address_space flag AS_CMTIME that is set atomically whenever the system transfers a pte dirty bit to a struct page backed by the address_space. This can happen with various locks held and when low on memory.

Later on, a new address_space op ->flush_cmtime is called at various points at which a filesystem should update timestamps if the file was previously modified through mmap.

The core changes have no effect on unmodified filesystems. To opt in, a filesystem should implement ->flush_ctime (most likely by using generic_flush_cmtime) and should avoid updating timestamps in ->page_mkwrite.

I've converted ext4. If it works well, it will be easy to convert all the other filesystems.

Changes from v2:
- The core code now interacts with filesystems only through address_space ops, so there should be fewer layering issues.
- MS_ASYNC is handled correctly.

Changes from v1:
- inode_update_time_writable now locks against the fs freezer.
- Minor cleanups.
- Major changelog improvements.

Andy Lutomirski (5):
mm: Track mappings that have been written via ptes
fs: Add inode_update_time_writable
mm: Notify filesystems when it's time to apply a deferred cmtime
update
mm: Scan for dirty ptes and update cmtime on MS_ASYNC
ext4: Defer mmap cmtime update until writeback

 fs/ext4/inode.c           |  4 ++-
 fs/inode.c                | 72 +++++++++++++++++++++++++++++++---------
 include/linux/fs.h        | 10 ++++++
 include/linux/pagemap.h   | 11 +++++++
 include/linux/writeback.h |  1 +
 mm/memory.c               |  7 +++-
 mm/mmap.c                 |  9 ++++-
 mm/msync.c                | 83 ++++++++++++++++++++++++++++++++++++++++-------
 mm/page-writeback.c       | 26 +++++++++++++++
 mm/rmap.c                 | 27 +++++++++++++--
 10 files changed, 219 insertions(+), 31 deletions(-)
Signature · 6 lines
1.8.3.1

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#1 lore raw

PATCH v3 1/5 mm: Track mappings that have been written via ptes

This will allow filesystems to identify when their mappings have
been modified using a pte. The idea is that, ideally, filesystems will update ctime and mtime sometime after any mmaped write.

This is handled in core mm code for two reasons:

1. Performance. Setting a bit directly is faster than an indirect call to a vma op.

2. Simplicity. The cmtime bit is set with lots of mm locks held. Rather than making filesystems add a new vm operation that needs to be aware of locking, it's easier to just get it right in core code.

For filesystems that don't use the deferred cmtime update mechanism, setting the AS_CMTIME bit has no effect.

---
 include/linux/pagemap.h | 11 +++++++++++
 mm/memory.c             |  7 ++++++-
 mm/rmap.c               | 27 +++++++++++++++++++++++++--
 3 files changed, 42 insertions(+), 3 deletions(-)
include/linux/pagemap.h +11 -0
index e3dea75..f98fe2d 100644
@@ -25,6 +25,7 @@ enum mapping_flags {
 	AS_MM_ALL_LOCKS	= __GFP_BITS_SHIFT + 2,	/* under mm_take_all_locks() */
 	AS_UNEVICTABLE	= __GFP_BITS_SHIFT + 3,	/* e.g., ramdisk, SHM_LOCK */
 	AS_BALLOON_MAP  = __GFP_BITS_SHIFT + 4, /* balloon page special map */
+	AS_CMTIME	= __GFP_BITS_SHIFT + 5, /* cmtime update deferred */
 };
 
 static inline void mapping_set_error(struct address_space *mapping, int error)
@@ -74,6 +75,16 @@ static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
 	return (__force gfp_t)mapping->flags & __GFP_BITS_MASK;
 }
 
+static inline void mapping_set_cmtime(struct address_space * mapping)
+{
+	set_bit(AS_CMTIME, &mapping->flags);
+}
+
+static inline bool mapping_test_clear_cmtime(struct address_space * mapping)
+{
+	return test_and_clear_bit(AS_CMTIME, &mapping->flags);
+}
+
 /*
  * This is non-atomic.  Only to be used before the mapping is activated.
  * Probably needs a barrier...
mm/memory.c +6 -1
index 4026841..1737a90 100644
@@ -1150,8 +1150,13 @@ again:
 			if (PageAnon(page))
 				rss[MM_ANONPAGES]--;
 			else {
-				if (pte_dirty(ptent))
+				if (pte_dirty(ptent)) {
+					struct address_space *mapping =
+						page_mapping(page);
+					if (mapping)
+						mapping_set_cmtime(mapping);
 					set_page_dirty(page);
+				}
 				if (pte_young(ptent) &&
 				    likely(!(vma->vm_flags & VM_SEQ_READ)))
 					mark_page_accessed(page);
mm/rmap.c +25 -2
index b2e29ac..2e3fb27 100644
@@ -928,6 +928,10 @@ static int page_mkclean_file(struct address_space *mapping, struct page *page)
 		}
 	}
 	mutex_unlock(&mapping->i_mmap_mutex);
+
+	if (ret)
+		mapping_set_cmtime(mapping);
+
 	return ret;
 }
 
@@ -1179,6 +1183,19 @@ out:
 }
 
 /*
+ * Mark a page's mapping for future cmtime update.  It's safe to call this
+ * on any page, but it only has any effect if the page is backed by a mapping
+ * that uses mapping_test_clear_cmtime to handle file time updates.  This means
+ * that there's no need to call this on for non-VM_SHARED vmas.
+ */
+static void page_set_cmtime(struct page *page)
+{
+	struct address_space *mapping = page_mapping(page);
+	if (mapping)
+		mapping_set_cmtime(mapping);
+}
+
+/*
  * Subfunctions of try_to_unmap: try_to_unmap_one called
  * repeatedly from try_to_unmap_ksm, try_to_unmap_anon or try_to_unmap_file.
  */
@@ -1219,8 +1236,11 @@ int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
 	pteval = ptep_clear_flush(vma, address, pte);
 
 	/* Move the dirty bit to the physical page now the pte is gone. */
-	if (pte_dirty(pteval))
+	if (pte_dirty(pteval)) {
 		set_page_dirty(page);
+		if (vma->vm_flags & VM_SHARED)
+			page_set_cmtime(page);
+	}
 
 	/* Update high watermark before we lower rss */
 	update_hiwater_rss(mm);
@@ -1413,8 +1433,11 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
 		}
 
 		/* Move the dirty bit to the physical page now the pte is gone. */
-		if (pte_dirty(pteval))
+		if (pte_dirty(pteval)) {
 			set_page_dirty(page);
+			if (vma->vm_flags & VM_SHARED)
+				page_set_cmtime(page);
+		}
 
 		page_remove_rmap(page);
 		page_cache_release(page);
Signature · 6 lines
1.8.3.1

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#2 lore raw

PATCH v3 2/5 fs: Add inode_update_time_writable

In reply to Andy Lutomirski

This is like file_update_time, except that it acts on a struct inode * instead of a struct file *.

---
 fs/inode.c         | 72 ++++++++++++++++++++++++++++++++++++++++++------------
 include/linux/fs.h |  1 +
 2 files changed, 58 insertions(+), 15 deletions(-)
fs/inode.c +57 -15
index d6dfb09..bc90c12 100644
@@ -1637,6 +1637,34 @@ int file_remove_suid(struct file *file)
 }
 EXPORT_SYMBOL(file_remove_suid);
 
+/*
+ * This does the work that's common to file_update_time and
+ * inode_update_time.
+ */
+static int prepare_update_cmtime(struct inode *inode, struct timespec *now)
+{
+	int sync_it;
+
+	/* First try to exhaust all avenues to not sync */
+	if (IS_NOCMTIME(inode))
+		return 0;
+
+	*now = current_fs_time(inode->i_sb);
+	if (!timespec_equal(&inode->i_mtime, now))
+		sync_it = S_MTIME;
+
+	if (!timespec_equal(&inode->i_ctime, now))
+		sync_it |= S_CTIME;
+
+	if (IS_I_VERSION(inode))
+		sync_it |= S_VERSION;
+
+	if (!sync_it)
+		return 0;
+
+	return sync_it;
+}
+
 /**
  *	file_update_time	-	update mtime and ctime time
  *	@file: file accessed
@@ -1654,23 +1682,9 @@ int file_update_time(struct file *file)
 {
 	struct inode *inode = file_inode(file);
 	struct timespec now;
-	int sync_it = 0;
+	int sync_it = prepare_update_cmtime(inode, &now);
 	int ret;
 
-	/* First try to exhaust all avenues to not sync */
-	if (IS_NOCMTIME(inode))
-		return 0;
-
-	now = current_fs_time(inode->i_sb);
-	if (!timespec_equal(&inode->i_mtime, &now))
-		sync_it = S_MTIME;
-
-	if (!timespec_equal(&inode->i_ctime, &now))
-		sync_it |= S_CTIME;
-
-	if (IS_I_VERSION(inode))
-		sync_it |= S_VERSION;
-
 	if (!sync_it)
 		return 0;
 
@@ -1685,6 +1699,34 @@ int file_update_time(struct file *file)
 }
 EXPORT_SYMBOL(file_update_time);
 
+/**
+ *	inode_update_time_writable	-	update mtime and ctime time
+ *	@inode: inode accessed
+ *
+ *	This is like file_update_time, but it assumes the mnt is writable
+ *	and takes an inode parameter instead.  (We need to assume the mnt
+ *	was writable because inodes aren't associated with any particular
+ *	mnt.
+ */
+
+int inode_update_time_writable(struct inode *inode)
+{
+	struct timespec now;
+	int sync_it = prepare_update_cmtime(inode, &now);
+	int ret;
+
+	if (!sync_it)
+		return 0;
+
+	/* sb_start_pagefault and update_time can both sleep. */
+	sb_start_pagefault(inode->i_sb);
+	ret = update_time(inode, &now, sync_it);
+	sb_end_pagefault(inode->i_sb);
+
+	return ret;
+}
+EXPORT_SYMBOL(inode_update_time_writable);
+
 int inode_needs_sync(struct inode *inode)
 {
 	if (IS_SYNC(inode))
include/linux/fs.h +1 -0
index 9818747..86cf0a4 100644
@@ -2590,6 +2590,7 @@ extern int inode_newsize_ok(const struct inode *, loff_t offset);
 extern void setattr_copy(struct inode *inode, const struct iattr *attr);
 
 extern int file_update_time(struct file *file);
+extern int inode_update_time_writable(struct inode *inode);
 
 extern int generic_show_options(struct seq_file *m, struct dentry *root);
 extern void save_mount_options(struct super_block *sb, char *options);
Signature · 6 lines
1.8.3.1

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#3 lore raw

Re: [PATCH v3 2/5] fs: Add inode_update_time_writable

Quoted 90 lines · Andy Lutomirski

This is like file_update_time, except that it acts on a struct inode * instead of a struct file *.

---
 fs/inode.c         | 72 ++++++++++++++++++++++++++++++++++++++++++------------
 include/linux/fs.h |  1 +
 2 files changed, 58 insertions(+), 15 deletions(-)
fs/inode.c +42 -15
index d6dfb09..bc90c12 100644
@@ -1637,6 +1637,34 @@ int file_remove_suid(struct file *file)
 }
 EXPORT_SYMBOL(file_remove_suid);
 
+/*
+ * This does the work that's common to file_update_time and
+ * inode_update_time.
+ */
+static int prepare_update_cmtime(struct inode *inode, struct timespec *now)
+{
+	int sync_it;
+
+	/* First try to exhaust all avenues to not sync */
+	if (IS_NOCMTIME(inode))
+		return 0;
+
+	*now = current_fs_time(inode->i_sb);
+	if (!timespec_equal(&inode->i_mtime, now))
+		sync_it = S_MTIME;
+
+	if (!timespec_equal(&inode->i_ctime, now))
+		sync_it |= S_CTIME;
+
+	if (IS_I_VERSION(inode))
+		sync_it |= S_VERSION;
+
+	if (!sync_it)
+		return 0;
+
+	return sync_it;
+}
+
 /**
  *	file_update_time	-	update mtime and ctime time
  *	@file: file accessed
@@ -1654,23 +1682,9 @@ int file_update_time(struct file *file)
 {
 	struct inode *inode = file_inode(file);
 	struct timespec now;
-	int sync_it = 0;
+	int sync_it = prepare_update_cmtime(inode, &now);
 	int ret;
 
-	/* First try to exhaust all avenues to not sync */
-	if (IS_NOCMTIME(inode))
-		return 0;
-
-	now = current_fs_time(inode->i_sb);
-	if (!timespec_equal(&inode->i_mtime, &now))
-		sync_it = S_MTIME;
-
-	if (!timespec_equal(&inode->i_ctime, &now))
-		sync_it |= S_CTIME;
-
-	if (IS_I_VERSION(inode))
-		sync_it |= S_VERSION;
-
 	if (!sync_it)
 		return 0;
 
@@ -1685,6 +1699,34 @@ int file_update_time(struct file *file)
 }
 EXPORT_SYMBOL(file_update_time);
 
+/**
+ *	inode_update_time_writable	-	update mtime and ctime time
+ *	@inode: inode accessed
+ *
+ *	This is like file_update_time, but it assumes the mnt is writable
+ *	and takes an inode parameter instead.  (We need to assume the mnt
+ *	was writable because inodes aren't associated with any particular
+ *	mnt.
+ */
+
+int inode_update_time_writable(struct inode *inode)
+{
+	struct timespec now;

fs/inode.c int file_update_time(struct file *file) · line 1724

Quoted 10 lines
fs/inode.c +10 -0
+	int sync_it = prepare_update_cmtime(inode, &now);
+	int ret;
+
+	if (!sync_it)
+		return 0;
+
+	/* sb_start_pagefault and update_time can both sleep. */
+	sb_start_pagefault(inode->i_sb);
+	ret = update_time(inode, &now, sync_it);
+	sb_end_pagefault(inode->i_sb);

This gets called from the writeback path - you can't use sb_start_pagefault/sb_end_pagefault in that path.

Cheers,

Dave.

Signature · 7 lines
Dave Chinner
[email protected]

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#4 lore raw

Re: [PATCH v3 2/5] fs: Add inode_update_time_writable

Quoted 10 lines · Dave Chinner
Quoted 9 lines · Andy Lutomirski

This is like file_update_time, except that it acts on a struct inode * instead of a struct file *.

---
 fs/inode.c         | 72 ++++++++++++++++++++++++++++++++++++++++++------------
 include/linux/fs.h |  1 +
 2 files changed, 58 insertions(+), 15 deletions(-)

[...]

Quoted 9 lines
Quoted 9 lines
fs/inode.c +9 -0
+
+int inode_update_time_writable(struct inode *inode)
+{
+     struct timespec now;
+     int sync_it = prepare_update_cmtime(inode, &now);
+     int ret;
+
+     if (!sync_it)
+             return 0;
Quoted 8 lines

fs/inode.c int file_update_time(struct file *file) · line 1724

Quoted 5 lines
fs/inode.c +5 -0
+
+     /* sb_start_pagefault and update_time can both sleep. */
+     sb_start_pagefault(inode->i_sb);
+     ret = update_time(inode, &now, sync_it);
+     sb_end_pagefault(inode->i_sb);

This gets called from the writeback path - you can't use sb_start_pagefault/sb_end_pagefault in that path.

The race I'm worried about is:

- mmap
- write to the mapping
- remount ro
- flush_cmtime -> inode_update_time_writable

This may be impossible, in which case I'm okay, but it's nice to have a sanity check. I'll see if I can figure out how to do that.

--Andy

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

#5 lore raw

Re: [PATCH v3 2/5] fs: Add inode_update_time_writable

Quoted 32 lines · Andy Lutomirski
Quoted 10 lines · Dave Chinner
Quoted 9 lines · Andy Lutomirski

This is like file_update_time, except that it acts on a struct inode * instead of a struct file *.

---
 fs/inode.c         | 72 ++++++++++++++++++++++++++++++++++++++++++------------
 include/linux/fs.h |  1 +
 2 files changed, 58 insertions(+), 15 deletions(-)

[...]

Quoted 9 lines
Quoted 9 lines
fs/inode.c +9 -0
+
+int inode_update_time_writable(struct inode *inode)
+{
+     struct timespec now;
+     int sync_it = prepare_update_cmtime(inode, &now);
+     int ret;
+
+     if (!sync_it)
+             return 0;
Quoted 8 lines

fs/inode.c int file_update_time(struct file *file) · line 1724

Quoted 5 lines
fs/inode.c +5 -0
+
+     /* sb_start_pagefault and update_time can both sleep. */
+     sb_start_pagefault(inode->i_sb);
+     ret = update_time(inode, &now, sync_it);
+     sb_end_pagefault(inode->i_sb);

This gets called from the writeback path - you can't use sb_start_pagefault/sb_end_pagefault in that path.

Quoted 6 lines

The race I'm worried about is:

- mmap
- write to the mapping
- remount ro
- flush_cmtime -> inode_update_time_writable

sb_start_pagefault() is for filesystem freeze protection, not remount-ro protection. If you freeze the filesystem, then we stop writes and pagefaults by making sb_start_pagefault/sb_start_write block, and then run writeback to clean all the pages. If writeback then blocks on sb_start_pagefault(), we've got a deadlock.

Quoted 2 lines

This may be impossible, in which case I'm okay, but it's nice to have a sanity check. I'll see if I can figure out how to do that.

The process of remount-ro should flush the dirty pages - the inode and page has been marked dirty by page_mkwrite(), after all.

Cheers,

Dave.

Signature · 7 lines
Dave Chinner
[email protected]

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#6 lore raw

Re: [PATCH v3 2/5] fs: Add inode_update_time_writable

Quoted 46 lines · Dave Chinner
Quoted 32 lines · Andy Lutomirski
Quoted 10 lines · Dave Chinner
Quoted 9 lines · Andy Lutomirski

This is like file_update_time, except that it acts on a struct inode * instead of a struct file *.

---
 fs/inode.c         | 72 ++++++++++++++++++++++++++++++++++++++++++------------
 include/linux/fs.h |  1 +
 2 files changed, 58 insertions(+), 15 deletions(-)

[...]

Quoted 9 lines
Quoted 9 lines
fs/inode.c +9 -0
+
+int inode_update_time_writable(struct inode *inode)
+{
+     struct timespec now;
+     int sync_it = prepare_update_cmtime(inode, &now);
+     int ret;
+
+     if (!sync_it)
+             return 0;
Quoted 8 lines

fs/inode.c int file_update_time(struct file *file) · line 1724

Quoted 5 lines
fs/inode.c +5 -0
+
+     /* sb_start_pagefault and update_time can both sleep. */
+     sb_start_pagefault(inode->i_sb);
+     ret = update_time(inode, &now, sync_it);
+     sb_end_pagefault(inode->i_sb);

This gets called from the writeback path - you can't use sb_start_pagefault/sb_end_pagefault in that path.

Quoted 6 lines

The race I'm worried about is:

- mmap
- write to the mapping
- remount ro
- flush_cmtime -> inode_update_time_writable

sb_start_pagefault() is for filesystem freeze protection, not remount-ro protection. If you freeze the filesystem, then we stop writes and pagefaults by making sb_start_pagefault/sb_start_write block, and then run writeback to clean all the pages. If writeback then blocks on sb_start_pagefault(), we've got a deadlock.

Quoted 5 lines
Quoted 2 lines

This may be impossible, in which case I'm okay, but it's nice to have a sanity check. I'll see if I can figure out how to do that.

The process of remount-ro should flush the dirty pages - the inode and page has been marked dirty by page_mkwrite(), after all.

Hmm. We can land in here from writeback, in which case the time should be updated unconditionally. We can also land in here from msync(MS_ASYNC) or munmap. munmap at least shouldn't block.

The nasty case is if a page is dirtied, then the frozen level is set to SB_FREEZE_PAGEFAULT, and then userspace calls munmap or msync *before* writepages gets called. In this case, blocking until the fs is unfrozen is probably impolite, and returning without updating the time is questionable.

Removing the check entirely may add a new race, though: what if .flush_cmtime has called mapping_test_clear_cmtime but hasn't gotten to updating the time yet when freezing finishes? This could be prevented by changing generic_flush_cmtime to do __sb_start_write(sb, SB_FREEZE_FS, false) and doing nothing if the fs is already frozen.

--Andy

maintainer
#7 lore raw

Re: [PATCH v3 2/5] fs: Add inode_update_time_writable

Quoted 63 lines · Andy Lutomirski
Quoted 46 lines · Dave Chinner
Quoted 32 lines · Andy Lutomirski
Quoted 10 lines · Dave Chinner
Quoted 9 lines · Andy Lutomirski

This is like file_update_time, except that it acts on a struct inode * instead of a struct file *.

---
 fs/inode.c         | 72 ++++++++++++++++++++++++++++++++++++++++++------------
 include/linux/fs.h |  1 +
 2 files changed, 58 insertions(+), 15 deletions(-)

[...]

Quoted 9 lines
Quoted 9 lines
fs/inode.c +9 -0
+
+int inode_update_time_writable(struct inode *inode)
+{
+     struct timespec now;
+     int sync_it = prepare_update_cmtime(inode, &now);
+     int ret;
+
+     if (!sync_it)
+             return 0;
Quoted 8 lines

fs/inode.c int file_update_time(struct file *file) · line 1724

Quoted 5 lines
fs/inode.c +5 -0
+
+     /* sb_start_pagefault and update_time can both sleep. */
+     sb_start_pagefault(inode->i_sb);
+     ret = update_time(inode, &now, sync_it);
+     sb_end_pagefault(inode->i_sb);

This gets called from the writeback path - you can't use sb_start_pagefault/sb_end_pagefault in that path.

Quoted 6 lines

The race I'm worried about is:

- mmap
- write to the mapping
- remount ro
- flush_cmtime -> inode_update_time_writable

sb_start_pagefault() is for filesystem freeze protection, not remount-ro protection. If you freeze the filesystem, then we stop writes and pagefaults by making sb_start_pagefault/sb_start_write block, and then run writeback to clean all the pages. If writeback then blocks on sb_start_pagefault(), we've got a deadlock.

Quoted 5 lines
Quoted 2 lines

This may be impossible, in which case I'm okay, but it's nice to have a sanity check. I'll see if I can figure out how to do that.

The process of remount-ro should flush the dirty pages - the inode and page has been marked dirty by page_mkwrite(), after all.

Hmm. We can land in here from writeback, in which case the time should be updated unconditionally. We can also land in here from msync(MS_ASYNC) or munmap. munmap at least shouldn't block.

The nasty case is if a page is dirtied, then the frozen level is set to SB_FREEZE_PAGEFAULT, and then userspace calls munmap or msync *before* writepages gets called. In this case, blocking until the fs is unfrozen is probably impolite, and returning without updating the time is questionable.

Quoted 5 lines

Removing the check entirely may add a new race, though: what if .flush_cmtime has called mapping_test_clear_cmtime but hasn't gotten to updating the time yet when freezing finishes? This could be prevented by changing generic_flush_cmtime to do __sb_start_write(sb, SB_FREEZE_FS, false) and doing nothing if the fs is already frozen.

I think it should be a responsibility of the caller of .flush_cmtime (as
is the case of update_time()) to handle freeze protection if needed. As Dave told you, writeback path mustn't actually take it. OTOH things like munmap() or msync() need to get it because we must avoid changing the filesystem when it is frozen and these calls can happen when fs is frozen.

Honza

Signature · 7 lines
Jan Kara <[email protected]>
SUSE Labs, CR

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#8 lore raw

PATCH v3 3/5 mm: Notify filesystems when it's time to apply a deferred cmtime update

In reply to Andy Lutomirski

Filesystems that defer cmtime updates should update cmtime when any of these events happen after a write via a mapping:

- The mapping is written back to disk. This happens from all kinds of places, all of which eventually call ->writepages.

- munmap is called or the mapping is removed when the process exits

- msync(MS_ASYNC) is called. Linux currently does nothing for msync(MS_ASYNC), but POSIX says that cmtime should be updated some time between an mmaped write and the subsequent msync call. MS_SYNC calls ->writepages, but MS_ASYNC needs special handling.

Filesystmes that defer cmtime updates should flush them on munmap or exit. Finding out that this happened through vm_ops is messy, so add a new address space op for this.

It's not strictly necessary to call ->flush_cmtime after ->writepages, but it simplifies the fs code. As an optional optimization, filesystems can call mapping_test_clear_cmtime themselves in ->writepages (as long as they're careful to scan all the pages first -- the cmtime bit may not be set when ->writepages is entered).

This patch does not implement the MS_ASYNC case; that's in the next patch.

---
 include/linux/fs.h        |  9 +++++++++
 include/linux/writeback.h |  1 +
 mm/mmap.c                 |  9 ++++++++-
 mm/page-writeback.c       | 26 ++++++++++++++++++++++++++
 4 files changed, 44 insertions(+), 1 deletion(-)
include/linux/fs.h +9 -0
index 86cf0a4..f224155 100644
@@ -350,6 +350,15 @@ struct address_space_operations {
 	/* Write back some dirty pages from this mapping. */
 	int (*writepages)(struct address_space *, struct writeback_control *);
 
+	/*
+	 * Userspace expects certain system calls to update cmtime if
+	 * a file has been recently written using a shared vma.  In
+	 * cases where cmtime may need to be updated but writepages is
+	 * not called, this is called instead.  (Implementations
+	 * should call mapping_test_clear_cmtime.)
+	 */
+	void (*flush_cmtime)(struct address_space *);
+
 	/* Set a page dirty.  Return true if this dirtied it */
 	int (*set_page_dirty)(struct page *page);
 
include/linux/writeback.h +1 -0
index 4e198ca..f6e8261 100644
@@ -174,6 +174,7 @@ typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc,
 
 int generic_writepages(struct address_space *mapping,
 		       struct writeback_control *wbc);
+void generic_flush_cmtime(struct address_space *mapping);
 void tag_pages_for_writeback(struct address_space *mapping,
 			     pgoff_t start, pgoff_t end);
 int write_cache_pages(struct address_space *mapping,
mm/mmap.c +8 -1
index 1edbaa3..7ed7700 100644
@@ -1,3 +1,4 @@
+
 /*
  * mm/mmap.c
  *
@@ -249,8 +250,14 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
 	might_sleep();
 	if (vma->vm_ops && vma->vm_ops->close)
 		vma->vm_ops->close(vma);
-	if (vma->vm_file)
+	if (vma->vm_file) {
+		if ((vma->vm_flags & VM_SHARED) && vma->vm_file->f_mapping) {
+			struct address_space *mapping = vma->vm_file->f_mapping;
+			if (mapping->a_ops && mapping->a_ops->flush_cmtime)
+				mapping->a_ops->flush_cmtime(mapping);
+		}
 		fput(vma->vm_file);
+	}
 	mpol_put(vma_policy(vma));
 	kmem_cache_free(vm_area_cachep, vma);
 	return next;
mm/page-writeback.c +26 -0
index 3f0c895..9ab8c9e 100644
@@ -1928,6 +1928,18 @@ int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
 		ret = mapping->a_ops->writepages(mapping, wbc);
 	else
 		ret = generic_writepages(mapping, wbc);
+
+	/*
+	 * ->writepages will call clear_page_dirty_for_io, which may, in turn,
+	 * mark the mapping for deferred cmtime update.  As an optimization,
+	 * a filesystem can flush the update at the end of ->writepages
+	 * (possibly avoiding a journal transaction, for example), but,
+	 * for simplicity, let filesystems skip that part and just implement
+	 * ->flush_cmtime.
+	 */
+	if (mapping->a_ops->flush_cmtime)
+		mapping->a_ops->flush_cmtime(mapping);
+
 	return ret;
 }
 
@@ -1970,6 +1982,20 @@ int write_one_page(struct page *page, int wait)
 }
 EXPORT_SYMBOL(write_one_page);
 
+/**
+ * generic_flush_cmtime - perform a deferred cmtime update if needed
+ * @mapping: address space structure
+ *
+ * This is a library function, which implements the flush_cmtime()
+ * address_space_operation.
+ */
+void generic_flush_cmtime(struct address_space *mapping)
+{
+	if (mapping_test_clear_cmtime(mapping))
+		inode_update_time_writable(mapping->host);
+}
+EXPORT_SYMBOL(generic_flush_cmtime);
+
 /*
  * For address_spaces which do not use buffers nor write back.
  */
Signature · 6 lines
1.8.3.1

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#9 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 17 lines · Andy Lutomirski

Filesystems that defer cmtime updates should update cmtime when any of these events happen after a write via a mapping:

- The mapping is written back to disk. This happens from all kinds of places, all of which eventually call ->writepages.

- munmap is called or the mapping is removed when the process exits

- msync(MS_ASYNC) is called. Linux currently does nothing for msync(MS_ASYNC), but POSIX says that cmtime should be updated some time between an mmaped write and the subsequent msync call. MS_SYNC calls ->writepages, but MS_ASYNC needs special handling.

Filesystmes that defer cmtime updates should flush them on munmap or exit. Finding out that this happened through vm_ops is messy, so add a new address space op for this.

Quoted 5 lines

It's not strictly necessary to call ->flush_cmtime after ->writepages, but it simplifies the fs code. As an optional optimization, filesystems can call mapping_test_clear_cmtime themselves in ->writepages (as long as they're careful to scan all the pages first -- the cmtime bit may not be set when ->writepages is entered).

.flush_cmtime is effectively a duplicate method. We already have .update_time to notify filesystems that they need to update the timestamp in the inode transactionally.

Indeed:

include/linux/fs.h struct address_space_operations { · line 360

Quoted 8 lines
include/linux/fs.h +8 -0
+	/*
+	 * Userspace expects certain system calls to update cmtime if
+	 * a file has been recently written using a shared vma.  In
+	 * cases where cmtime may need to be updated but writepages is
+	 * not called, this is called instead.  (Implementations
+	 * should call mapping_test_clear_cmtime.)
+	 */
+	void (*flush_cmtime)(struct address_space *);

You say it can be implemented in the ->writepage(s) method, and all filesystems provide ->writepage(s) in some form. Therefore I would have thought it be best to simply require filesystems to check that mapping flag during those methods and update the inode directly when that is set?

Indeed, the way you've set up the infrastructure, we'll have to rewrite the cmtime update code to enable writepages to update this within some other transaction. Perhaps you should just implement it that way first?

Quoted 7 lines
mm/page-writeback.c +1 -0
@@ -1928,6 +1928,18 @@ int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
 		ret = mapping->a_ops->writepages(mapping, wbc);
 	else
 		ret = generic_writepages(mapping, wbc);
+

mm/page-writeback.c int do_writepages(struct address_space *mapping, struct writeback_control *wbc) · line 1941

Quoted 10 lines
mm/page-writeback.c +10 -0
+	/*
+	 * ->writepages will call clear_page_dirty_for_io, which may, in turn,
+	 * mark the mapping for deferred cmtime update.  As an optimization,
+	 * a filesystem can flush the update at the end of ->writepages
+	 * (possibly avoiding a journal transaction, for example), but,
+	 * for simplicity, let filesystems skip that part and just implement
+	 * ->flush_cmtime.
+	 */
+	if (mapping->a_ops->flush_cmtime)
+		mapping->a_ops->flush_cmtime(mapping);

And that's where you cannot call sb_pagefault_start/end....

Cheers,

Dave.

Signature · 7 lines
Dave Chinner
[email protected]

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#10 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 24 lines · Dave Chinner
Quoted 17 lines · Andy Lutomirski

Filesystems that defer cmtime updates should update cmtime when any of these events happen after a write via a mapping:

- The mapping is written back to disk. This happens from all kinds of places, all of which eventually call ->writepages.

- munmap is called or the mapping is removed when the process exits

- msync(MS_ASYNC) is called. Linux currently does nothing for msync(MS_ASYNC), but POSIX says that cmtime should be updated some time between an mmaped write and the subsequent msync call. MS_SYNC calls ->writepages, but MS_ASYNC needs special handling.

Filesystmes that defer cmtime updates should flush them on munmap or exit. Finding out that this happened through vm_ops is messy, so add a new address space op for this.

Quoted 5 lines

It's not strictly necessary to call ->flush_cmtime after ->writepages, but it simplifies the fs code. As an optional optimization, filesystems can call mapping_test_clear_cmtime themselves in ->writepages (as long as they're careful to scan all the pages first -- the cmtime bit may not be set when ->writepages is entered).

Quoted 3 lines

.flush_cmtime is effectively a duplicate method. We already have .update_time to notify filesystems that they need to update the timestamp in the inode transactionally.

.update_time is used for the atime update as well, and it relies on the core code to update the in-memory timestamp first. I used that approach in v2, but it was (correctly, I think) pointed out that this was a layering violation and that core code shouldn't be mucking with the timestamps directly during writeback.

There was a recent effort to move most of the file_update_calls from the core into .page_mkwrite, and I don't think anyone wants to undo that.

Quoted 12 lines

Indeed:

include/linux/fs.h struct address_space_operations { · line 360

Quoted 8 lines
include/linux/fs.h +8 -0
+     /*
+      * Userspace expects certain system calls to update cmtime if
+      * a file has been recently written using a shared vma.  In
+      * cases where cmtime may need to be updated but writepages is
+      * not called, this is called instead.  (Implementations
+      * should call mapping_test_clear_cmtime.)
+      */
+     void (*flush_cmtime)(struct address_space *);
Quoted 5 lines

You say it can be implemented in the ->writepage(s) method, and all filesystems provide ->writepage(s) in some form. Therefore I would have thought it be best to simply require filesystems to check that mapping flag during those methods and update the inode directly when that is set?

The problem with only doing it in ->writepages is that calling writepages from munmap and exit would probably hurt performance for no particular gain. So I need some kind of callback to say "update the time, but don't write data." The AS_CMTIME bit will still be set when the ptes are removed.

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

Quoted 5 lines

Indeed, the way you've set up the infrastructure, we'll have to rewrite the cmtime update code to enable writepages to update this within some other transaction. Perhaps you should just implement it that way first?

This is already possible although not IMO necessary for correctness. All that ext4 would need to do is to add something like:

if (mapping_test_clear_cmtime(mapping)) {
update times within current transaction
}

somewhere inside the transaction in writepages. There would probably be room for some kind of generic helper to do everything in inode_update_time_writable except for the actual mark_inode_dirty part, but this still seems nasty from a locking perspective, and I'd rather leave that optimization to an ext4 developer who wants to do it.

I could simplify this a bit by moving the mapping_test_clear_cmtime part from .flush_cmtime to its callers.

--Andy

#11 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 25 lines · Andy Lutomirski
Quoted 24 lines · Dave Chinner
Quoted 22 lines · Andy Lutomirski

Filesystems that defer cmtime updates should update cmtime when any of these events happen after a write via a mapping:

- The mapping is written back to disk. This happens from all kinds of places, all of which eventually call ->writepages.

- munmap is called or the mapping is removed when the process exits

- msync(MS_ASYNC) is called. Linux currently does nothing for msync(MS_ASYNC), but POSIX says that cmtime should be updated some time between an mmaped write and the subsequent msync call. MS_SYNC calls ->writepages, but MS_ASYNC needs special handling.

Filesystmes that defer cmtime updates should flush them on munmap or exit. Finding out that this happened through vm_ops is messy, so add a new address space op for this.

It's not strictly necessary to call ->flush_cmtime after ->writepages, but it simplifies the fs code. As an optional optimization, filesystems can call mapping_test_clear_cmtime themselves in ->writepages (as long as they're careful to scan all the pages first -- the cmtime bit may not be set when ->writepages is entered).

Quoted 6 lines
Quoted 3 lines

.flush_cmtime is effectively a duplicate method. We already have .update_time to notify filesystems that they need to update the timestamp in the inode transactionally.

.update_time is used for the atime update as well, and it relies on the core code to update the in-memory timestamp first.

No, it doesn't. The caller of .update_time provides the timestamp to that gets written into the relevant fields of the inode.

i.e. this code:

	now = current_fs_time(inode->i_sb);
	if (inode->i_op->update_time)
		return inode->i_op->update_time(inode, &now, S_CTIME|S_MTIME);

will update *only* the ctime and mtime of the inode to have a value of @now. That's precisely what you want to do, yes?

Indeed, your .flush_cmtime function effectively does:

	flags = prepare_cmtime(inode, &now)
		{ *now = current_fs_time()
		  flags = S_CTIME|S_MTIME;
		}
	update_time(inode, now, flags);
		{
			inode->i_op->update_time(inode, now, flags)
			or
			mark_inode_dirty_sync()
		}

IOWs, you're adding a filesystem specific method to update a timestamp that wraps around a generic method for updating a timestamp. i.e. .flush_cmtime is not necessary - you could just call inode_update_time_writable() from generic_writepages() and it would simply just work for all filesystems....

Quoted 4 lines

I used that
approach in v2, but it was (correctly, I think) pointed out that this was a layering violation and that core code shouldn't be mucking with the timestamps directly during writeback.

If calling a generic method to update the timestamp is a layering violation, then why is replacing that with a filesystem specific method of updating a timestamp not a layering violation?

Quoted 17 lines
Quoted 11 lines

Indeed:

include/linux/fs.h struct address_space_operations { · line 360

Quoted 8 lines
include/linux/fs.h +8 -0
+     /*
+      * Userspace expects certain system calls to update cmtime if
+      * a file has been recently written using a shared vma.  In
+      * cases where cmtime may need to be updated but writepages is
+      * not called, this is called instead.  (Implementations
+      * should call mapping_test_clear_cmtime.)
+      */
+     void (*flush_cmtime)(struct address_space *);
Quoted 5 lines

You say it can be implemented in the ->writepage(s) method, and all filesystems provide ->writepage(s) in some form. Therefore I would have thought it be best to simply require filesystems to check that mapping flag during those methods and update the inode directly when that is set?

Quoted 5 lines

The problem with only doing it in ->writepages is that calling writepages from munmap and exit would probably hurt performance for no particular gain. So I need some kind of callback to say "update the time, but don't write data." The AS_CMTIME bit will still be set when the ptes are removed.

What's the point of updating the timestamp at unmap when it's going to be changed again when the writeback occurs?

Quoted 3 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

And some filesystems provide a .writepages method that doesn't call .writepage, so those filesystems will need to do the timestamp update in those methods.

Quoted 11 lines
Quoted 4 lines

Indeed, the way you've set up the infrastructure, we'll have to rewrite the cmtime update code to enable writepages to update this within some other transaction. Perhaps you should just implement it that way first?

This is already possible although not IMO necessary for correctness. All that ext4 would need to do is to add something like:

if (mapping_test_clear_cmtime(mapping)) {
update times within current transaction
}

Where does it get the timestamps from? i.e. the update could call prepare_update_cmtime() to do this, yes? And so having a wrapper that does

	if (mapping_test_clear_cmtime(mapping))
		return prepare_update_cmtime(inode);
	return 0;

would work just fine for them, yes?

Quoted 6 lines

somewhere inside the transaction in writepages. There would probably be room for some kind of generic helper to do everything in inode_update_time_writable except for the actual mark_inode_dirty part, but this still seems nasty from a locking perspective, and I'd rather leave that optimization to an ext4 developer who wants to do it.

filesystems that implement .update_time don't need to mark the struct inode dirty on timestamp updates. Similarly, filesystems that use a writepages transaction to do the update don't either....

Cheers,

Dave.

Signature · 7 lines
Dave Chinner
[email protected]

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#12 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 58 lines · Dave Chinner
Quoted 25 lines · Andy Lutomirski
Quoted 24 lines · Dave Chinner
Quoted 22 lines · Andy Lutomirski

Filesystems that defer cmtime updates should update cmtime when any of these events happen after a write via a mapping:

- The mapping is written back to disk. This happens from all kinds of places, all of which eventually call ->writepages.

- munmap is called or the mapping is removed when the process exits

- msync(MS_ASYNC) is called. Linux currently does nothing for msync(MS_ASYNC), but POSIX says that cmtime should be updated some time between an mmaped write and the subsequent msync call. MS_SYNC calls ->writepages, but MS_ASYNC needs special handling.

Filesystmes that defer cmtime updates should flush them on munmap or exit. Finding out that this happened through vm_ops is messy, so add a new address space op for this.

It's not strictly necessary to call ->flush_cmtime after ->writepages, but it simplifies the fs code. As an optional optimization, filesystems can call mapping_test_clear_cmtime themselves in ->writepages (as long as they're careful to scan all the pages first -- the cmtime bit may not be set when ->writepages is entered).

Quoted 6 lines
Quoted 3 lines

.flush_cmtime is effectively a duplicate method. We already have .update_time to notify filesystems that they need to update the timestamp in the inode transactionally.

.update_time is used for the atime update as well, and it relies on the core code to update the in-memory timestamp first.

No, it doesn't. The caller of .update_time provides the timestamp to that gets written into the relevant fields of the inode.

i.e. this code:

        now = current_fs_time(inode->i_sb);
        if (inode->i_op->update_time)
                return inode->i_op->update_time(inode, &now, S_CTIME|S_MTIME);

will update *only* the ctime and mtime of the inode to have a value of @now. That's precisely what you want to do, yes?

Indeed, your .flush_cmtime function effectively does:

        flags = prepare_cmtime(inode, &now)
                { *now = current_fs_time()
                  flags = S_CTIME|S_MTIME;
                }
        update_time(inode, now, flags);
                {
                        inode->i_op->update_time(inode, now, flags)
                        or
                        mark_inode_dirty_sync()
                }
Quoted 5 lines

IOWs, you're adding a filesystem specific method to update a timestamp that wraps around a generic method for updating a timestamp. i.e. .flush_cmtime is not necessary - you could just call inode_update_time_writable() from generic_writepages() and it would simply just work for all filesystems....

OK, I'll try that out.

Quoted 27 lines
Quoted 5 lines

I used that
approach in v2, but it was (correctly, I think) pointed out that this was a layering violation and that core code shouldn't be mucking with the timestamps directly during writeback.

If calling a generic method to update the timestamp is a layering violation, then why is replacing that with a filesystem specific method of updating a timestamp not a layering violation?

Quoted 17 lines
Quoted 16 lines

Indeed:

include/linux/fs.h struct address_space_operations { · line 360

Quoted 8 lines
include/linux/fs.h +8 -0
+     /*
+      * Userspace expects certain system calls to update cmtime if
+      * a file has been recently written using a shared vma.  In
+      * cases where cmtime may need to be updated but writepages is
+      * not called, this is called instead.  (Implementations
+      * should call mapping_test_clear_cmtime.)
+      */
+     void (*flush_cmtime)(struct address_space *);

You say it can be implemented in the ->writepage(s) method, and all filesystems provide ->writepage(s) in some form. Therefore I would have thought it be best to simply require filesystems to check that mapping flag during those methods and update the inode directly when that is set?

Quoted 8 lines
Quoted 5 lines

The problem with only doing it in ->writepages is that calling writepages from munmap and exit would probably hurt performance for no particular gain. So I need some kind of callback to say "update the time, but don't write data." The AS_CMTIME bit will still be set when the ptes are removed.

What's the point of updating the timestamp at unmap when it's going to be changed again when the writeback occurs?

To avoid breaking make and similar tools. Suppose that an output file already exists but is stale. Some program gets called to update it, and it opens it for write, mmaps it, updates it, calls munmap, and exits. Its parent will expect the timestamp to have been updated, but writeback may not have happened.

Quoted 10 lines
Quoted 4 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

Last time I checked, all the paths that actually needed the timestamp update went through .writepages. I'll double-check.

Quoted 34 lines

And some filesystems provide a .writepages method that doesn't call .writepage, so those filesystems will need to do the timestamp update in those methods.

Quoted 11 lines
Quoted 4 lines

Indeed, the way you've set up the infrastructure, we'll have to rewrite the cmtime update code to enable writepages to update this within some other transaction. Perhaps you should just implement it that way first?

This is already possible although not IMO necessary for correctness. All that ext4 would need to do is to add something like:

if (mapping_test_clear_cmtime(mapping)) {
update times within current transaction
}

Where does it get the timestamps from? i.e. the update could call prepare_update_cmtime() to do this, yes? And so having a wrapper that does

        if (mapping_test_clear_cmtime(mapping))
                return prepare_update_cmtime(inode);
        return 0;

would work just fine for them, yes?

Quoted 6 lines

somewhere inside the transaction in writepages. There would probably be room for some kind of generic helper to do everything in inode_update_time_writable except for the actual mark_inode_dirty part, but this still seems nasty from a locking perspective, and I'd rather leave that optimization to an ext4 developer who wants to do it.

Quoted 3 lines

filesystems that implement .update_time don't need to mark the struct inode dirty on timestamp updates. Similarly, filesystems that use a writepages transaction to do the update don't either....

Fair enough. I'll spin a v4 and see how it looks.

--Andy

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

maintainer
#13 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 4 lines · Andy Lutomirski
Quoted 4 lines
Quoted 3 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

Quoted 8 lines
Quoted 5 lines

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

Last time I checked, all the paths that actually needed the timestamp update went through .writepages. I'll double-check.

kswapd can call just .writepage to do the writeout so timestamp update
should be handled there as well. Otherwise all pages in a mapping can be cleaned without timestamp being updated.

Which btw made me realize that even your scheme doesn't completely make sure timestamp is updated after mmap write - if you have pages 0 and 1, you write to both of them - CMTIME flag gets set. Then fsync_range(fd, 0, 4096) is called. We write the page 0, writeprotect it, update timestamps. But page 1 is still writeable so writes to it won't set CMTIME flag, neither update the timestamp... Not that I think this can be reasonably solved but it is a food for thought.

Honza

Signature · 7 lines
Jan Kara <[email protected]>
SUSE Labs, CR

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#14 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 11 lines · Jan Kara
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines
Quoted 3 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

Quoted 5 lines
Quoted 2 lines

Last time I checked, all the paths that actually needed the timestamp update went through .writepages. I'll double-check.

kswapd can call just .writepage to do the writeout so timestamp update
should be handled there as well. Otherwise all pages in a mapping can be cleaned without timestamp being updated.

OK, I'll fix that.

Quoted 8 lines

Which btw made me realize that even your scheme doesn't completely make sure timestamp is updated after mmap write - if you have pages 0 and 1, you write to both of them - CMTIME flag gets set. Then fsync_range(fd, 0, 4096) is called. We write the page 0, writeprotect it, update timestamps. But page 1 is still writeable so writes to it won't set CMTIME flag, neither update the timestamp... Not that I think this can be reasonably solved but it is a food for thought.

This should already work. AS_CMTIME is set when the pte goes from dirty to clean, not when the pte goes from wp to writable. So whenever clear_page_dirty_for_io is called on page 1, AS_CMTIME will be set and a subsequent writepages call will update the timestamp.

--Andy

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

#15 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 12 lines · Andy Lutomirski
Quoted 11 lines · Jan Kara
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines
Quoted 3 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Last time I checked, all the paths that actually needed the timestamp update went through .writepages. I'll double-check.

kswapd can call just .writepage to do the writeout so timestamp update
should be handled there as well. Otherwise all pages in a mapping can be cleaned without timestamp being updated.

OK, I'll fix that.

This is a bit ugly. mpage_writepages and generic_writepages both call ->writepage. If writepage starts checking cmtime, then writepages will do multiple timestamp updates on filesystems that use this code.

I can modify vmscan and migrate to flush cmtime -- they seem to be the only callers of ->writepage that aren't themselves called from ->writepages.

--Andy

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

#16 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

In reply to Andy Lutomirski
Quoted 29 lines · Andy Lutomirski
Quoted 11 lines · Jan Kara
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines
Quoted 3 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

Quoted 5 lines
Quoted 2 lines

Last time I checked, all the paths that actually needed the timestamp update went through .writepages. I'll double-check.

kswapd can call just .writepage to do the writeout so timestamp update
should be handled there as well. Otherwise all pages in a mapping can be cleaned without timestamp being updated.

OK, I'll fix that.

Quoted 8 lines

Which btw made me realize that even your scheme doesn't completely make sure timestamp is updated after mmap write - if you have pages 0 and 1, you write to both of them - CMTIME flag gets set. Then fsync_range(fd, 0, 4096) is called. We write the page 0, writeprotect it, update timestamps. But page 1 is still writeable so writes to it won't set CMTIME flag, neither update the timestamp... Not that I think this can be reasonably solved but it is a food for thought.

Quoted 4 lines

This should already work. AS_CMTIME is set when the pte goes from dirty to clean, not when the pte goes from wp to writable. So whenever clear_page_dirty_for_io is called on page 1, AS_CMTIME will be set and a subsequent writepages call will update the timestamp.

Oh, I missed that - I thought you were setting AS_CMTIME during .page_mkwrite.

Setting it in clear_page_dirty_for_io() is too late for filesystems to include it in their existing transactions during .writepage, (at least for XFs and ext4) because they do their delayed allocation transactions before changing page state....

Cheers,

Dave.

Signature · 2 lines
Dave Chinner
[email protected]
#17 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 35 lines · Dave Chinner
Quoted 29 lines · Andy Lutomirski
Quoted 11 lines · Jan Kara
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines
Quoted 3 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

Quoted 5 lines
Quoted 2 lines

Last time I checked, all the paths that actually needed the timestamp update went through .writepages. I'll double-check.

kswapd can call just .writepage to do the writeout so timestamp update
should be handled there as well. Otherwise all pages in a mapping can be cleaned without timestamp being updated.

OK, I'll fix that.

Quoted 8 lines

Which btw made me realize that even your scheme doesn't completely make sure timestamp is updated after mmap write - if you have pages 0 and 1, you write to both of them - CMTIME flag gets set. Then fsync_range(fd, 0, 4096) is called. We write the page 0, writeprotect it, update timestamps. But page 1 is still writeable so writes to it won't set CMTIME flag, neither update the timestamp... Not that I think this can be reasonably solved but it is a food for thought.

Quoted 4 lines

This should already work. AS_CMTIME is set when the pte goes from dirty to clean, not when the pte goes from wp to writable. So whenever clear_page_dirty_for_io is called on page 1, AS_CMTIME will be set and a subsequent writepages call will update the timestamp.

Quoted 7 lines

Oh, I missed that - I thought you were setting AS_CMTIME during .page_mkwrite.

Setting it in clear_page_dirty_for_io() is too late for filesystems to include it in their existing transactions during .writepage, (at least for XFs and ext4) because they do their delayed allocation transactions before changing page state....

Couldn't it go between mpage_map_and_submit_extent and ext4_journal_stop in ext4_writepages?

Quoted 7 lines

Cheers,

Dave.
--
Dave Chinner
[email protected]

Signature · 7 lines
Andy Lutomirski
AMA Capital Management, LLC

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#18 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 39 lines · Andy Lutomirski
Quoted 38 lines · Dave Chinner
Quoted 29 lines · Andy Lutomirski
Quoted 11 lines · Jan Kara
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines
Quoted 3 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

Quoted 5 lines
Quoted 2 lines

Last time I checked, all the paths that actually needed the timestamp update went through .writepages. I'll double-check.

kswapd can call just .writepage to do the writeout so timestamp update
should be handled there as well. Otherwise all pages in a mapping can be cleaned without timestamp being updated.

OK, I'll fix that.

Quoted 8 lines

Which btw made me realize that even your scheme doesn't completely make sure timestamp is updated after mmap write - if you have pages 0 and 1, you write to both of them - CMTIME flag gets set. Then fsync_range(fd, 0, 4096) is called. We write the page 0, writeprotect it, update timestamps. But page 1 is still writeable so writes to it won't set CMTIME flag, neither update the timestamp... Not that I think this can be reasonably solved but it is a food for thought.

Quoted 4 lines

This should already work. AS_CMTIME is set when the pte goes from dirty to clean, not when the pte goes from wp to writable. So whenever clear_page_dirty_for_io is called on page 1, AS_CMTIME will be set and a subsequent writepages call will update the timestamp.

Oh, I missed that - I thought you were setting AS_CMTIME during .page_mkwrite.

Quoted 7 lines
Quoted 4 lines

Setting it in clear_page_dirty_for_io() is too late for filesystems to include it in their existing transactions during .writepage, (at least for XFs and ext4) because they do their delayed allocation transactions before changing page state....

Couldn't it go between mpage_map_and_submit_extent and ext4_journal_stop in ext4_writepages?

Maybe - I'm not an ext4 expert - but even if you can make it work for ext4 in some way, that doesn't mean it is possible for any other filesystem to use the same method. You're adding code to generic, non-filesystem specific code paths and so the solutions need to be generic rather not tied to how a specific filesystem is implemented.

Cheers,

Dave.

Signature · 7 lines
Dave Chinner
[email protected]

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#19 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 45 lines · Dave Chinner
Quoted 44 lines · Andy Lutomirski
Quoted 42 lines · Dave Chinner
Quoted 29 lines · Andy Lutomirski
Quoted 11 lines · Jan Kara
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines
Quoted 3 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

Quoted 5 lines
Quoted 2 lines

Last time I checked, all the paths that actually needed the timestamp update went through .writepages. I'll double-check.

kswapd can call just .writepage to do the writeout so timestamp update
should be handled there as well. Otherwise all pages in a mapping can be cleaned without timestamp being updated.

OK, I'll fix that.

Quoted 8 lines

Which btw made me realize that even your scheme doesn't completely make sure timestamp is updated after mmap write - if you have pages 0 and 1, you write to both of them - CMTIME flag gets set. Then fsync_range(fd, 0, 4096) is called. We write the page 0, writeprotect it, update timestamps. But page 1 is still writeable so writes to it won't set CMTIME flag, neither update the timestamp... Not that I think this can be reasonably solved but it is a food for thought.

Quoted 4 lines

This should already work. AS_CMTIME is set when the pte goes from dirty to clean, not when the pte goes from wp to writable. So whenever clear_page_dirty_for_io is called on page 1, AS_CMTIME will be set and a subsequent writepages call will update the timestamp.

Oh, I missed that - I thought you were setting AS_CMTIME during .page_mkwrite.

Setting it in clear_page_dirty_for_io() is too late for filesystems to include it in their existing transactions during .writepage, (at least for XFs and ext4) because they do their delayed allocation transactions before changing page state....

Quoted 9 lines
Quoted 2 lines

Couldn't it go between mpage_map_and_submit_extent and ext4_journal_stop in ext4_writepages?

Maybe - I'm not an ext4 expert - but even if you can make it work for ext4 in some way, that doesn't mean it is possible for any other filesystem to use the same method. You're adding code to generic, non-filesystem specific code paths and so the solutions need to be generic rather not tied to how a specific filesystem is implemented.

I don't see the problem for xfs or btrfs either.

xfs uses generic_writepages, which already does the right thing. (xfs with my updated patches passes my tests.) xfs_vm_writepage calls xfs_start_page_writeback(..., 1, ...), so clear_page_dirty_for_io is called. At that point (I presume), it would still be possible to add metadata to a transaction (assuming there's a transaction open -- I don't have a clue here). Even if this is too late, xfs_vm_writepage could call page_mkwrite to for AS_CMTIME to be set if needed. page_mkwrite will be fast if the page isn't mmapped. What am I missing?

btrfs seems to do much the same thing.

--Andy

Quoted 6 lines

Cheers,

Dave.
--
Dave Chinner
[email protected]

Signature · 7 lines
Andy Lutomirski
AMA Capital Management, LLC

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#20 lore raw

Re: [PATCH v3 3/5] mm: Notify filesystems when it's time to apply a deferred cmtime update

Quoted 56 lines · Andy Lutomirski
Quoted 45 lines · Dave Chinner
Quoted 44 lines · Andy Lutomirski
Quoted 42 lines · Dave Chinner
Quoted 29 lines · Andy Lutomirski
Quoted 11 lines · Jan Kara
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines
Quoted 3 lines

I could require ->writepages *and* ->flush_cmtime to handle the time update, but that would complicate non-transactional filesystems. Those filesystems should just flush cmtime at the end of writepages.

do_writepages() is the wrong place to do such updates - we can get writeback directly through .writepage, so the time updates need to be in .writepage. That first .writepage call will clear the bit on the mapping, so it's only done on the first call to .writepage on the given mapping.

Quoted 5 lines
Quoted 2 lines

Last time I checked, all the paths that actually needed the timestamp update went through .writepages. I'll double-check.

kswapd can call just .writepage to do the writeout so timestamp update
should be handled there as well. Otherwise all pages in a mapping can be cleaned without timestamp being updated.

OK, I'll fix that.

Quoted 8 lines

Which btw made me realize that even your scheme doesn't completely make sure timestamp is updated after mmap write - if you have pages 0 and 1, you write to both of them - CMTIME flag gets set. Then fsync_range(fd, 0, 4096) is called. We write the page 0, writeprotect it, update timestamps. But page 1 is still writeable so writes to it won't set CMTIME flag, neither update the timestamp... Not that I think this can be reasonably solved but it is a food for thought.

Quoted 4 lines

This should already work. AS_CMTIME is set when the pte goes from dirty to clean, not when the pte goes from wp to writable. So whenever clear_page_dirty_for_io is called on page 1, AS_CMTIME will be set and a subsequent writepages call will update the timestamp.

Oh, I missed that - I thought you were setting AS_CMTIME during .page_mkwrite.

Setting it in clear_page_dirty_for_io() is too late for filesystems to include it in their existing transactions during .writepage, (at least for XFs and ext4) because they do their delayed allocation transactions before changing page state....

Quoted 9 lines
Quoted 2 lines

Couldn't it go between mpage_map_and_submit_extent and ext4_journal_stop in ext4_writepages?

Maybe - I'm not an ext4 expert - but even if you can make it work for ext4 in some way, that doesn't mean it is possible for any other filesystem to use the same method. You're adding code to generic, non-filesystem specific code paths and so the solutions need to be generic rather not tied to how a specific filesystem is implemented.

Quoted 8 lines

I don't see the problem for xfs or btrfs either.

xfs uses generic_writepages, which already does the right thing. (xfs with my updated patches passes my tests.) xfs_vm_writepage calls xfs_start_page_writeback(..., 1, ...), so clear_page_dirty_for_io is called. At that point (I presume), it would still be possible to add metadata to a transaction (assuming there's a transaction open -- I don't have a clue here).

That's my point - there isn't a transaction in XFS at this point, and so if we gather that flag from clear_page_dirty_for_io() we'd need a second transaction and therefore the optimisation you want filesystems to use to mitigate the additional overhead can't be done for all commonly used filesystems.

Quoted 4 lines

Even if this is too late, xfs_vm_writepage
could call page_mkwrite to for AS_CMTIME to be set if needed. page_mkwrite will be fast if the page isn't mmapped. What am I missing?

That it leads to different behaviour for different filesystems.

i.e. page_mkwrite on page A sets the flag. writeback on a range that doesn't include page A occurs, sees the flag, clears it after updating the timestamp. Some time later writeback on page A occurs, no timestamp update occurs.

The behaviour needs to be consistent across filesystems.

Cheers,

Dave.

Signature · 7 lines
Dave Chinner
[email protected]

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#21 lore raw

PATCH v3 4/5 mm: Scan for dirty ptes and update cmtime on MS_ASYNC

In reply to Andy Lutomirski

This is probably unimportant but improves POSIX compliance.

---
 mm/msync.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 72 insertions(+), 11 deletions(-)
mm/msync.c +72 -11
index 632df45..9e41acd 100644
@@ -13,13 +13,16 @@
 #include <linux/file.h>
 #include <linux/syscalls.h>
 #include <linux/sched.h>
+#include <linux/rmap.h>
+#include <linux/pagemap.h>
 
 /*
  * MS_SYNC syncs the entire file - including mappings.
  *
  * MS_ASYNC does not start I/O (it used to, up to 2.5.67).
  * Nor does it marks the relevant pages dirty (it used to up to 2.6.17).
- * Now it doesn't do anything, since dirty pages are properly tracked.
+ * Now all it does is ensure that file timestamps get updated, since POSIX
+ * requires it.  We track dirty pages correct without MS_ASYNC.
  *
  * The application may now run fsync() to
  * write out the dirty pages and wait on the writeout and check the result.
@@ -28,6 +31,57 @@
  * So by _not_ starting I/O in MS_ASYNC we provide complete flexibility to
  * applications.
  */
+
+static int msync_async_range(struct vm_area_struct *vma,
+			      unsigned long *start, unsigned long end)
+{
+	struct mm_struct *mm;
+	struct address_space *mapping;
+	int iters = 0;
+
+	while (*start < end && *start < vma->vm_end && iters < 128) {
+		unsigned int page_mask, page_increm;
+
+		/*
+		 * Require that the pte writable (because otherwise it can't
+		 * be dirty, so there's nothing to clean).
+		 *
+		 * In theory we could check the pte dirty bit, but this is
+		 * awkward and barely worth it.
+		 */
+		struct page *page = follow_page_mask(vma, *start,
+						     FOLL_GET | FOLL_WRITE,
+						     &page_mask);
+
+		if (page && !IS_ERR(page)) {
+			if (lock_page_killable(page) == 0) {
+				page_mkclean(page);
+				unlock_page(page);
+			}
+			put_page(page);
+		}
+
+		if (IS_ERR(page))
+			return PTR_ERR(page);
+
+		page_increm = 1 + (~(*start >> PAGE_SHIFT) & page_mask);
+		*start += page_increm * PAGE_SIZE;
+		cond_resched();
+		iters++;
+	}
+
+	/* XXX: try to do this only once? */
+	mapping = vma->vm_file->f_mapping;
+	if (mapping->a_ops->flush_cmtime)
+		mapping->a_ops->flush_cmtime(mapping);
+
+	/* Give mmap_sem writers a chance. */
+	mm = current->mm;
+	up_read(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
+	return 0;
+}
+
 SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags)
 {
 	unsigned long end;
@@ -77,18 +131,25 @@ SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags)
 			goto out_unlock;
 		}
 		file = vma->vm_file;
-		start = vma->vm_end;
-		if ((flags & MS_SYNC) && file &&
-				(vma->vm_flags & VM_SHARED)) {
-			get_file(file);
-			up_read(&mm->mmap_sem);
-			error = vfs_fsync(file, 0);
-			fput(file);
-			if (error || start >= end)
-				goto out;
-			down_read(&mm->mmap_sem);
+		if (file && vma->vm_flags & VM_SHARED) {
+			if (flags & MS_SYNC) {
+				start = vma->vm_end;
+				get_file(file);
+				up_read(&mm->mmap_sem);
+				error = vfs_fsync(file, 0);
+				fput(file);
+				if (error || start >= end)
+					goto out;
+				down_read(&mm->mmap_sem);
+			} else if ((vma->vm_flags & VM_WRITE) &&
+				   file->f_mapping) {
+				error = msync_async_range(vma, &start, end);
+			} else {
+				start = vma->vm_end;
+			}
 			vma = find_vma(mm, start);
 		} else {
+			start = vma->vm_end;
 			if (start >= end) {
 				error = 0;
 				goto out_unlock;
Signature · 6 lines
1.8.3.1

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#22 lore raw

PATCH v3 5/5 ext4: Defer mmap cmtime update until writeback

In reply to Andy Lutomirski

A fancier implementation could probably avoid an extra journal transaction by adding a mapping_test_clear_cmtime call in ext4_writepages, but this should already be a considerable improvement -- we'll start one transaction per writepages call instead of one per page.

---
 fs/ext4/inode.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
fs/ext4/inode.c +3 -1
index dd32a2e..cee6b45 100644
@@ -3236,6 +3236,7 @@ static const struct address_space_operations ext4_aops = {
 	.readpages		= ext4_readpages,
 	.writepage		= ext4_writepage,
 	.writepages		= ext4_writepages,
+	.flush_cmtime		= generic_flush_cmtime,
 	.write_begin		= ext4_write_begin,
 	.write_end		= ext4_write_end,
 	.bmap			= ext4_bmap,
@@ -3252,6 +3253,7 @@ static const struct address_space_operations ext4_journalled_aops = {
 	.readpages		= ext4_readpages,
 	.writepage		= ext4_writepage,
 	.writepages		= ext4_writepages,
+	.flush_cmtime		= generic_flush_cmtime,
 	.write_begin		= ext4_write_begin,
 	.write_end		= ext4_journalled_write_end,
 	.set_page_dirty		= ext4_journalled_set_page_dirty,
@@ -3268,6 +3270,7 @@ static const struct address_space_operations ext4_da_aops = {
 	.readpages		= ext4_readpages,
 	.writepage		= ext4_writepage,
 	.writepages		= ext4_writepages,
+	.flush_cmtime		= generic_flush_cmtime,
 	.write_begin		= ext4_da_write_begin,
 	.write_end		= ext4_da_write_end,
 	.bmap			= ext4_bmap,
@@ -5025,7 +5028,6 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 	int retries = 0;
 
 	sb_start_pagefault(inode->i_sb);
-	file_update_time(vma->vm_file);
 	/* Delalloc case is easy... */
 	if (test_opt(inode->i_sb, DELALLOC) &&
 	    !ext4_should_journal_data(inode) &&
Signature · 6 lines
1.8.3.1

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
#23 lore raw

Re: [PATCH v3 5/5] ext4: Defer mmap cmtime update until writeback

Quoted 5 lines · Andy Lutomirski

A fancier implementation could probably avoid an extra journal transaction by adding a mapping_test_clear_cmtime call in ext4_writepages, but this should already be a considerable improvement -- we'll start one transaction per writepages call instead of one per page.

I'd like to see more than just an ext4 implementation - btrfs and XFS are the other main filesystems that should behave identically.

Also, it's worthwhile to write a generic xfstest to ensure that they all update the timestamp appropriately - if its' in xfstests, then we can basically guarantee that it won't get randomly regressed in future, and other filesystems can be easily verified as well sa their implement this.

Cheers,

Dave.

Signature · 2 lines
Dave Chinner
[email protected]
#24 lore raw

Re: [PATCH v3 5/5] ext4: Defer mmap cmtime update until writeback

Quoted 9 lines · Dave Chinner
Quoted 5 lines · Andy Lutomirski

A fancier implementation could probably avoid an extra journal transaction by adding a mapping_test_clear_cmtime call in ext4_writepages, but this should already be a considerable improvement -- we'll start one transaction per writepages call instead of one per page.

I'd like to see more than just an ext4 implementation - btrfs and XFS are the other main filesystems that should behave identically.

Will do.

Quoted 7 lines

Also, it's worthwhile to write a generic xfstest to ensure that they all update the timestamp appropriately - if its' in xfstests, then we can basically guarantee that it won't get randomly regressed in future, and other filesystems can be easily verified as well sa their implement this.

Is there a guide to writing an xfstest? I've already written it as a standalone C program, so I assume it's easy.

--Andy

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

#25 lore raw

Re: [PATCH v3 5/5] ext4: Defer mmap cmtime update until writeback

Quoted 14 lines · Andy Lutomirski
Quoted 9 lines · Dave Chinner
Quoted 5 lines · Andy Lutomirski

A fancier implementation could probably avoid an extra journal transaction by adding a mapping_test_clear_cmtime call in ext4_writepages, but this should already be a considerable improvement -- we'll start one transaction per writepages call instead of one per page.

I'd like to see more than just an ext4 implementation - btrfs and XFS are the other main filesystems that should behave identically.

Will do.

Quoted 1 line
Quoted 8 lines
Quoted 6 lines

Also, it's worthwhile to write a generic xfstest to ensure that they all update the timestamp appropriately - if its' in xfstests, then we can basically guarantee that it won't get randomly regressed in future, and other filesystems can be easily verified as well sa their implement this.

Is there a guide to writing an xfstest?

Yes. see the readme file in the root directory of the repository.

Cheers,

Dave.

Signature · 7 lines
Dave Chinner
[email protected]

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs