Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eed2179e authored by Brian Foster's avatar Brian Foster Committed by Miklos Szeredi
Browse files

fuse: invalidate inode mapping if mtime changes



We currently invalidate the inode address space mapping
if the file size changes unexpectedly. In the case of a
fuse network filesystem, a portion of a file could be
overwritten remotely without changing the file size.
Compare the old mtime as well to detect this condition
and invalidate the mapping if the file has been updated.

The original logic (to ignore changes in mtime) is
preserved unless the client specifies FUSE_AUTO_INVAL_DATA
on init.

Signed-off-by: default avatarBrian Foster <bfoster@redhat.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent 72d0d248
Loading
Loading
Loading
Loading
+24 −3
Original line number Original line Diff line number Diff line
@@ -197,6 +197,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
	struct fuse_conn *fc = get_fuse_conn(inode);
	struct fuse_conn *fc = get_fuse_conn(inode);
	struct fuse_inode *fi = get_fuse_inode(inode);
	struct fuse_inode *fi = get_fuse_inode(inode);
	loff_t oldsize;
	loff_t oldsize;
	struct timespec old_mtime;


	spin_lock(&fc->lock);
	spin_lock(&fc->lock);
	if (attr_version != 0 && fi->attr_version > attr_version) {
	if (attr_version != 0 && fi->attr_version > attr_version) {
@@ -204,14 +205,34 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
		return;
		return;
	}
	}


	old_mtime = inode->i_mtime;
	fuse_change_attributes_common(inode, attr, attr_valid);
	fuse_change_attributes_common(inode, attr, attr_valid);


	oldsize = inode->i_size;
	oldsize = inode->i_size;
	i_size_write(inode, attr->size);
	i_size_write(inode, attr->size);
	spin_unlock(&fc->lock);
	spin_unlock(&fc->lock);


	if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
	if (S_ISREG(inode->i_mode)) {
		bool inval = false;

		if (oldsize != attr->size) {
			truncate_pagecache(inode, oldsize, attr->size);
			truncate_pagecache(inode, oldsize, attr->size);
			inval = true;
		} else if (fc->auto_inval_data) {
			struct timespec new_mtime = {
				.tv_sec = attr->mtime,
				.tv_nsec = attr->mtimensec,
			};

			/*
			 * Auto inval mode also checks and invalidates if mtime
			 * has changed.
			 */
			if (!timespec_equal(&old_mtime, &new_mtime))
				inval = true;
		}

		if (inval)
			invalidate_inode_pages2(inode->i_mapping);
			invalidate_inode_pages2(inode->i_mapping);
	}
	}
}
}