18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * High-level sync()-related operations
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/file.h>
88c2ecf20Sopenharmony_ci#include <linux/fs.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/export.h>
118c2ecf20Sopenharmony_ci#include <linux/namei.h>
128c2ecf20Sopenharmony_ci#include <linux/sched.h>
138c2ecf20Sopenharmony_ci#include <linux/writeback.h>
148c2ecf20Sopenharmony_ci#include <linux/syscalls.h>
158c2ecf20Sopenharmony_ci#include <linux/linkage.h>
168c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
178c2ecf20Sopenharmony_ci#include <linux/quotaops.h>
188c2ecf20Sopenharmony_ci#include <linux/backing-dev.h>
198c2ecf20Sopenharmony_ci#include "internal.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
228c2ecf20Sopenharmony_ci			SYNC_FILE_RANGE_WAIT_AFTER)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * Write out and wait upon all dirty data associated with this
268c2ecf20Sopenharmony_ci * superblock.  Filesystem data as well as the underlying block
278c2ecf20Sopenharmony_ci * device.  Takes the superblock lock.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_ciint sync_filesystem(struct super_block *sb)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	int ret = 0;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	/*
348c2ecf20Sopenharmony_ci	 * We need to be protected against the filesystem going from
358c2ecf20Sopenharmony_ci	 * r/o to r/w or vice versa.
368c2ecf20Sopenharmony_ci	 */
378c2ecf20Sopenharmony_ci	WARN_ON(!rwsem_is_locked(&sb->s_umount));
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	/*
408c2ecf20Sopenharmony_ci	 * No point in syncing out anything if the filesystem is read-only.
418c2ecf20Sopenharmony_ci	 */
428c2ecf20Sopenharmony_ci	if (sb_rdonly(sb))
438c2ecf20Sopenharmony_ci		return 0;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/*
468c2ecf20Sopenharmony_ci	 * Do the filesystem syncing work.  For simple filesystems
478c2ecf20Sopenharmony_ci	 * writeback_inodes_sb(sb) just dirties buffers with inodes so we have
488c2ecf20Sopenharmony_ci	 * to submit I/O for these buffers via __sync_blockdev().  This also
498c2ecf20Sopenharmony_ci	 * speeds up the wait == 1 case since in that case write_inode()
508c2ecf20Sopenharmony_ci	 * methods call sync_dirty_buffer() and thus effectively write one block
518c2ecf20Sopenharmony_ci	 * at a time.
528c2ecf20Sopenharmony_ci	 */
538c2ecf20Sopenharmony_ci	writeback_inodes_sb(sb, WB_REASON_SYNC);
548c2ecf20Sopenharmony_ci	if (sb->s_op->sync_fs) {
558c2ecf20Sopenharmony_ci		ret = sb->s_op->sync_fs(sb, 0);
568c2ecf20Sopenharmony_ci		if (ret)
578c2ecf20Sopenharmony_ci			return ret;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci	ret = __sync_blockdev(sb->s_bdev, 0);
608c2ecf20Sopenharmony_ci	if (ret)
618c2ecf20Sopenharmony_ci		return ret;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	sync_inodes_sb(sb);
648c2ecf20Sopenharmony_ci	if (sb->s_op->sync_fs) {
658c2ecf20Sopenharmony_ci		ret = sb->s_op->sync_fs(sb, 1);
668c2ecf20Sopenharmony_ci		if (ret)
678c2ecf20Sopenharmony_ci			return ret;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci	return __sync_blockdev(sb->s_bdev, 1);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sync_filesystem);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void sync_inodes_one_sb(struct super_block *sb, void *arg)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	if (!sb_rdonly(sb))
768c2ecf20Sopenharmony_ci		sync_inodes_sb(sb);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic void sync_fs_one_sb(struct super_block *sb, void *arg)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	if (!sb_rdonly(sb) && !(sb->s_iflags & SB_I_SKIP_SYNC) &&
828c2ecf20Sopenharmony_ci	    sb->s_op->sync_fs)
838c2ecf20Sopenharmony_ci		sb->s_op->sync_fs(sb, *(int *)arg);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void fdatawrite_one_bdev(struct block_device *bdev, void *arg)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	filemap_fdatawrite(bdev->bd_inode->i_mapping);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic void fdatawait_one_bdev(struct block_device *bdev, void *arg)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	/*
948c2ecf20Sopenharmony_ci	 * We keep the error status of individual mapping so that
958c2ecf20Sopenharmony_ci	 * applications can catch the writeback error using fsync(2).
968c2ecf20Sopenharmony_ci	 * See filemap_fdatawait_keep_errors() for details.
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	filemap_fdatawait_keep_errors(bdev->bd_inode->i_mapping);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/*
1028c2ecf20Sopenharmony_ci * Sync everything. We start by waking flusher threads so that most of
1038c2ecf20Sopenharmony_ci * writeback runs on all devices in parallel. Then we sync all inodes reliably
1048c2ecf20Sopenharmony_ci * which effectively also waits for all flusher threads to finish doing
1058c2ecf20Sopenharmony_ci * writeback. At this point all data is on disk so metadata should be stable
1068c2ecf20Sopenharmony_ci * and we tell filesystems to sync their metadata via ->sync_fs() calls.
1078c2ecf20Sopenharmony_ci * Finally, we writeout all block devices because some filesystems (e.g. ext2)
1088c2ecf20Sopenharmony_ci * just write metadata (such as inodes or bitmaps) to block device page cache
1098c2ecf20Sopenharmony_ci * and do not sync it on their own in ->sync_fs().
1108c2ecf20Sopenharmony_ci */
1118c2ecf20Sopenharmony_civoid ksys_sync(void)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	int nowait = 0, wait = 1;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	wakeup_flusher_threads(WB_REASON_SYNC);
1168c2ecf20Sopenharmony_ci	iterate_supers(sync_inodes_one_sb, NULL);
1178c2ecf20Sopenharmony_ci	iterate_supers(sync_fs_one_sb, &nowait);
1188c2ecf20Sopenharmony_ci	iterate_supers(sync_fs_one_sb, &wait);
1198c2ecf20Sopenharmony_ci	iterate_bdevs(fdatawrite_one_bdev, NULL);
1208c2ecf20Sopenharmony_ci	iterate_bdevs(fdatawait_one_bdev, NULL);
1218c2ecf20Sopenharmony_ci	if (unlikely(laptop_mode))
1228c2ecf20Sopenharmony_ci		laptop_sync_completion();
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciSYSCALL_DEFINE0(sync)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	ksys_sync();
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void do_sync_work(struct work_struct *work)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	int nowait = 0;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/*
1368c2ecf20Sopenharmony_ci	 * Sync twice to reduce the possibility we skipped some inodes / pages
1378c2ecf20Sopenharmony_ci	 * because they were temporarily locked
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci	iterate_supers(sync_inodes_one_sb, &nowait);
1408c2ecf20Sopenharmony_ci	iterate_supers(sync_fs_one_sb, &nowait);
1418c2ecf20Sopenharmony_ci	iterate_bdevs(fdatawrite_one_bdev, NULL);
1428c2ecf20Sopenharmony_ci	iterate_supers(sync_inodes_one_sb, &nowait);
1438c2ecf20Sopenharmony_ci	iterate_supers(sync_fs_one_sb, &nowait);
1448c2ecf20Sopenharmony_ci	iterate_bdevs(fdatawrite_one_bdev, NULL);
1458c2ecf20Sopenharmony_ci	printk("Emergency Sync complete\n");
1468c2ecf20Sopenharmony_ci	kfree(work);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_civoid emergency_sync(void)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct work_struct *work;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	work = kmalloc(sizeof(*work), GFP_ATOMIC);
1548c2ecf20Sopenharmony_ci	if (work) {
1558c2ecf20Sopenharmony_ci		INIT_WORK(work, do_sync_work);
1568c2ecf20Sopenharmony_ci		schedule_work(work);
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/*
1618c2ecf20Sopenharmony_ci * sync a single super
1628c2ecf20Sopenharmony_ci */
1638c2ecf20Sopenharmony_ciSYSCALL_DEFINE1(syncfs, int, fd)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct fd f = fdget(fd);
1668c2ecf20Sopenharmony_ci	struct super_block *sb;
1678c2ecf20Sopenharmony_ci	int ret, ret2;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (!f.file)
1708c2ecf20Sopenharmony_ci		return -EBADF;
1718c2ecf20Sopenharmony_ci	sb = f.file->f_path.dentry->d_sb;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	down_read(&sb->s_umount);
1748c2ecf20Sopenharmony_ci	ret = sync_filesystem(sb);
1758c2ecf20Sopenharmony_ci	up_read(&sb->s_umount);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	ret2 = errseq_check_and_advance(&sb->s_wb_err, &f.file->f_sb_err);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	fdput(f);
1808c2ecf20Sopenharmony_ci	return ret ? ret : ret2;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci/**
1848c2ecf20Sopenharmony_ci * vfs_fsync_range - helper to sync a range of data & metadata to disk
1858c2ecf20Sopenharmony_ci * @file:		file to sync
1868c2ecf20Sopenharmony_ci * @start:		offset in bytes of the beginning of data range to sync
1878c2ecf20Sopenharmony_ci * @end:		offset in bytes of the end of data range (inclusive)
1888c2ecf20Sopenharmony_ci * @datasync:		perform only datasync
1898c2ecf20Sopenharmony_ci *
1908c2ecf20Sopenharmony_ci * Write back data in range @start..@end and metadata for @file to disk.  If
1918c2ecf20Sopenharmony_ci * @datasync is set only metadata needed to access modified file data is
1928c2ecf20Sopenharmony_ci * written.
1938c2ecf20Sopenharmony_ci */
1948c2ecf20Sopenharmony_ciint vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct inode *inode = file->f_mapping->host;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (!file->f_op->fsync)
1998c2ecf20Sopenharmony_ci		return -EINVAL;
2008c2ecf20Sopenharmony_ci	if (!datasync && (inode->i_state & I_DIRTY_TIME))
2018c2ecf20Sopenharmony_ci		mark_inode_dirty_sync(inode);
2028c2ecf20Sopenharmony_ci	return file->f_op->fsync(file, start, end, datasync);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vfs_fsync_range);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/**
2078c2ecf20Sopenharmony_ci * vfs_fsync - perform a fsync or fdatasync on a file
2088c2ecf20Sopenharmony_ci * @file:		file to sync
2098c2ecf20Sopenharmony_ci * @datasync:		only perform a fdatasync operation
2108c2ecf20Sopenharmony_ci *
2118c2ecf20Sopenharmony_ci * Write back data and metadata for @file to disk.  If @datasync is
2128c2ecf20Sopenharmony_ci * set only metadata needed to access modified file data is written.
2138c2ecf20Sopenharmony_ci */
2148c2ecf20Sopenharmony_ciint vfs_fsync(struct file *file, int datasync)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	return vfs_fsync_range(file, 0, LLONG_MAX, datasync);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vfs_fsync);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic int do_fsync(unsigned int fd, int datasync)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct fd f = fdget(fd);
2238c2ecf20Sopenharmony_ci	int ret = -EBADF;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (f.file) {
2268c2ecf20Sopenharmony_ci		ret = vfs_fsync(f.file, datasync);
2278c2ecf20Sopenharmony_ci		fdput(f);
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci	return ret;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ciSYSCALL_DEFINE1(fsync, unsigned int, fd)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	return do_fsync(fd, 0);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ciSYSCALL_DEFINE1(fdatasync, unsigned int, fd)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	return do_fsync(fd, 1);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ciint sync_file_range(struct file *file, loff_t offset, loff_t nbytes,
2438c2ecf20Sopenharmony_ci		    unsigned int flags)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	int ret;
2468c2ecf20Sopenharmony_ci	struct address_space *mapping;
2478c2ecf20Sopenharmony_ci	loff_t endbyte;			/* inclusive */
2488c2ecf20Sopenharmony_ci	umode_t i_mode;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	ret = -EINVAL;
2518c2ecf20Sopenharmony_ci	if (flags & ~VALID_FLAGS)
2528c2ecf20Sopenharmony_ci		goto out;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	endbyte = offset + nbytes;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if ((s64)offset < 0)
2578c2ecf20Sopenharmony_ci		goto out;
2588c2ecf20Sopenharmony_ci	if ((s64)endbyte < 0)
2598c2ecf20Sopenharmony_ci		goto out;
2608c2ecf20Sopenharmony_ci	if (endbyte < offset)
2618c2ecf20Sopenharmony_ci		goto out;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if (sizeof(pgoff_t) == 4) {
2648c2ecf20Sopenharmony_ci		if (offset >= (0x100000000ULL << PAGE_SHIFT)) {
2658c2ecf20Sopenharmony_ci			/*
2668c2ecf20Sopenharmony_ci			 * The range starts outside a 32 bit machine's
2678c2ecf20Sopenharmony_ci			 * pagecache addressing capabilities.  Let it "succeed"
2688c2ecf20Sopenharmony_ci			 */
2698c2ecf20Sopenharmony_ci			ret = 0;
2708c2ecf20Sopenharmony_ci			goto out;
2718c2ecf20Sopenharmony_ci		}
2728c2ecf20Sopenharmony_ci		if (endbyte >= (0x100000000ULL << PAGE_SHIFT)) {
2738c2ecf20Sopenharmony_ci			/*
2748c2ecf20Sopenharmony_ci			 * Out to EOF
2758c2ecf20Sopenharmony_ci			 */
2768c2ecf20Sopenharmony_ci			nbytes = 0;
2778c2ecf20Sopenharmony_ci		}
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	if (nbytes == 0)
2818c2ecf20Sopenharmony_ci		endbyte = LLONG_MAX;
2828c2ecf20Sopenharmony_ci	else
2838c2ecf20Sopenharmony_ci		endbyte--;		/* inclusive */
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	i_mode = file_inode(file)->i_mode;
2868c2ecf20Sopenharmony_ci	ret = -ESPIPE;
2878c2ecf20Sopenharmony_ci	if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
2888c2ecf20Sopenharmony_ci			!S_ISLNK(i_mode))
2898c2ecf20Sopenharmony_ci		goto out;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	mapping = file->f_mapping;
2928c2ecf20Sopenharmony_ci	ret = 0;
2938c2ecf20Sopenharmony_ci	if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) {
2948c2ecf20Sopenharmony_ci		ret = file_fdatawait_range(file, offset, endbyte);
2958c2ecf20Sopenharmony_ci		if (ret < 0)
2968c2ecf20Sopenharmony_ci			goto out;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (flags & SYNC_FILE_RANGE_WRITE) {
3008c2ecf20Sopenharmony_ci		int sync_mode = WB_SYNC_NONE;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		if ((flags & SYNC_FILE_RANGE_WRITE_AND_WAIT) ==
3038c2ecf20Sopenharmony_ci			     SYNC_FILE_RANGE_WRITE_AND_WAIT)
3048c2ecf20Sopenharmony_ci			sync_mode = WB_SYNC_ALL;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		ret = __filemap_fdatawrite_range(mapping, offset, endbyte,
3078c2ecf20Sopenharmony_ci						 sync_mode);
3088c2ecf20Sopenharmony_ci		if (ret < 0)
3098c2ecf20Sopenharmony_ci			goto out;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (flags & SYNC_FILE_RANGE_WAIT_AFTER)
3138c2ecf20Sopenharmony_ci		ret = file_fdatawait_range(file, offset, endbyte);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ciout:
3168c2ecf20Sopenharmony_ci	return ret;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci/*
3208c2ecf20Sopenharmony_ci * ksys_sync_file_range() permits finely controlled syncing over a segment of
3218c2ecf20Sopenharmony_ci * a file in the range offset .. (offset+nbytes-1) inclusive.  If nbytes is
3228c2ecf20Sopenharmony_ci * zero then ksys_sync_file_range() will operate from offset out to EOF.
3238c2ecf20Sopenharmony_ci *
3248c2ecf20Sopenharmony_ci * The flag bits are:
3258c2ecf20Sopenharmony_ci *
3268c2ecf20Sopenharmony_ci * SYNC_FILE_RANGE_WAIT_BEFORE: wait upon writeout of all pages in the range
3278c2ecf20Sopenharmony_ci * before performing the write.
3288c2ecf20Sopenharmony_ci *
3298c2ecf20Sopenharmony_ci * SYNC_FILE_RANGE_WRITE: initiate writeout of all those dirty pages in the
3308c2ecf20Sopenharmony_ci * range which are not presently under writeback. Note that this may block for
3318c2ecf20Sopenharmony_ci * significant periods due to exhaustion of disk request structures.
3328c2ecf20Sopenharmony_ci *
3338c2ecf20Sopenharmony_ci * SYNC_FILE_RANGE_WAIT_AFTER: wait upon writeout of all pages in the range
3348c2ecf20Sopenharmony_ci * after performing the write.
3358c2ecf20Sopenharmony_ci *
3368c2ecf20Sopenharmony_ci * Useful combinations of the flag bits are:
3378c2ecf20Sopenharmony_ci *
3388c2ecf20Sopenharmony_ci * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE: ensures that all pages
3398c2ecf20Sopenharmony_ci * in the range which were dirty on entry to ksys_sync_file_range() are placed
3408c2ecf20Sopenharmony_ci * under writeout.  This is a start-write-for-data-integrity operation.
3418c2ecf20Sopenharmony_ci *
3428c2ecf20Sopenharmony_ci * SYNC_FILE_RANGE_WRITE: start writeout of all dirty pages in the range which
3438c2ecf20Sopenharmony_ci * are not presently under writeout.  This is an asynchronous flush-to-disk
3448c2ecf20Sopenharmony_ci * operation.  Not suitable for data integrity operations.
3458c2ecf20Sopenharmony_ci *
3468c2ecf20Sopenharmony_ci * SYNC_FILE_RANGE_WAIT_BEFORE (or SYNC_FILE_RANGE_WAIT_AFTER): wait for
3478c2ecf20Sopenharmony_ci * completion of writeout of all pages in the range.  This will be used after an
3488c2ecf20Sopenharmony_ci * earlier SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE operation to wait
3498c2ecf20Sopenharmony_ci * for that operation to complete and to return the result.
3508c2ecf20Sopenharmony_ci *
3518c2ecf20Sopenharmony_ci * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER
3528c2ecf20Sopenharmony_ci * (a.k.a. SYNC_FILE_RANGE_WRITE_AND_WAIT):
3538c2ecf20Sopenharmony_ci * a traditional sync() operation.  This is a write-for-data-integrity operation
3548c2ecf20Sopenharmony_ci * which will ensure that all pages in the range which were dirty on entry to
3558c2ecf20Sopenharmony_ci * ksys_sync_file_range() are written to disk.  It should be noted that disk
3568c2ecf20Sopenharmony_ci * caches are not flushed by this call, so there are no guarantees here that the
3578c2ecf20Sopenharmony_ci * data will be available on disk after a crash.
3588c2ecf20Sopenharmony_ci *
3598c2ecf20Sopenharmony_ci *
3608c2ecf20Sopenharmony_ci * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any
3618c2ecf20Sopenharmony_ci * I/O errors or ENOSPC conditions and will return those to the caller, after
3628c2ecf20Sopenharmony_ci * clearing the EIO and ENOSPC flags in the address_space.
3638c2ecf20Sopenharmony_ci *
3648c2ecf20Sopenharmony_ci * It should be noted that none of these operations write out the file's
3658c2ecf20Sopenharmony_ci * metadata.  So unless the application is strictly performing overwrites of
3668c2ecf20Sopenharmony_ci * already-instantiated disk blocks, there are no guarantees here that the data
3678c2ecf20Sopenharmony_ci * will be available after a crash.
3688c2ecf20Sopenharmony_ci */
3698c2ecf20Sopenharmony_ciint ksys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
3708c2ecf20Sopenharmony_ci			 unsigned int flags)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	int ret;
3738c2ecf20Sopenharmony_ci	struct fd f;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	ret = -EBADF;
3768c2ecf20Sopenharmony_ci	f = fdget(fd);
3778c2ecf20Sopenharmony_ci	if (f.file)
3788c2ecf20Sopenharmony_ci		ret = sync_file_range(f.file, offset, nbytes, flags);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	fdput(f);
3818c2ecf20Sopenharmony_ci	return ret;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ciSYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes,
3858c2ecf20Sopenharmony_ci				unsigned int, flags)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	return ksys_sync_file_range(fd, offset, nbytes, flags);
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci/* It would be nice if people remember that not all the world's an i386
3918c2ecf20Sopenharmony_ci   when they introduce new system calls */
3928c2ecf20Sopenharmony_ciSYSCALL_DEFINE4(sync_file_range2, int, fd, unsigned int, flags,
3938c2ecf20Sopenharmony_ci				 loff_t, offset, loff_t, nbytes)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	return ksys_sync_file_range(fd, offset, nbytes, flags);
3968c2ecf20Sopenharmony_ci}
397