diff options
Diffstat (limited to 'fs/direct-io.c')
| -rw-r--r-- | fs/direct-io.c | 24 | 
1 files changed, 23 insertions, 1 deletions
diff --git a/fs/direct-io.c b/fs/direct-io.c index 3aafb3343a65..a0ca9e48e993 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -219,6 +219,27 @@ static inline struct page *dio_get_page(struct dio *dio,  	return dio->pages[sdio->head];  } +/* + * Warn about a page cache invalidation failure during a direct io write. + */ +void dio_warn_stale_pagecache(struct file *filp) +{ +	static DEFINE_RATELIMIT_STATE(_rs, 86400 * HZ, DEFAULT_RATELIMIT_BURST); +	char pathname[128]; +	struct inode *inode = file_inode(filp); +	char *path; + +	errseq_set(&inode->i_mapping->wb_err, -EIO); +	if (__ratelimit(&_rs)) { +		path = file_path(filp, pathname, sizeof(pathname)); +		if (IS_ERR(path)) +			path = "(unknown)"; +		pr_crit("Page cache invalidation failure on direct I/O.  Possible data corruption due to collision with buffered I/O!\n"); +		pr_crit("File: %s PID: %d Comm: %.20s\n", path, current->pid, +			current->comm); +	} +} +  /**   * dio_complete() - called when all DIO BIO I/O has been completed   * @offset: the byte offset in the file of the completed operation @@ -290,7 +311,8 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, unsigned int flags)  		err = invalidate_inode_pages2_range(dio->inode->i_mapping,  					offset >> PAGE_SHIFT,  					(offset + ret - 1) >> PAGE_SHIFT); -		WARN_ON_ONCE(err); +		if (err) +			dio_warn_stale_pagecache(dio->iocb->ki_filp);  	}  	if (!(dio->flags & DIO_SKIP_DIO_COUNT))  |