diff --git a/fs/sync.c b/fs/sync.c index b54e0541ad89..01e82170545a 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -234,6 +234,77 @@ SYSCALL_DEFINE1(fdatasync, unsigned int, fd) return do_fsync(fd, 1); } +int sync_file_range(struct file *file, loff_t offset, loff_t nbytes, + unsigned int flags) +{ + int ret; + struct address_space *mapping; + loff_t endbyte; /* inclusive */ + umode_t i_mode; + + ret = -EINVAL; + if (flags & ~VALID_FLAGS) + goto out; + + endbyte = offset + nbytes; + + if ((s64)offset < 0) + goto out; + if ((s64)endbyte < 0) + goto out; + if (endbyte < offset) + goto out; + + if (sizeof(pgoff_t) == 4) { + if (offset >= (0x100000000ULL << PAGE_SHIFT)) { + /* + * The range starts outside a 32 bit machine's + * pagecache addressing capabilities. Let it "succeed" + */ + ret = 0; + goto out; + } + if (endbyte >= (0x100000000ULL << PAGE_SHIFT)) { + /* + * Out to EOF + */ + nbytes = 0; + } + } + + if (nbytes == 0) + endbyte = LLONG_MAX; + else + endbyte--; /* inclusive */ + + i_mode = file_inode(file)->i_mode; + ret = -ESPIPE; + if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) && + !S_ISLNK(i_mode)) + goto out; + + mapping = file->f_mapping; + ret = 0; + if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) { + ret = file_fdatawait_range(file, offset, endbyte); + if (ret < 0) + goto out; + } + + if (flags & SYNC_FILE_RANGE_WRITE) { + ret = __filemap_fdatawrite_range(mapping, offset, endbyte, + WB_SYNC_NONE); + if (ret < 0) + goto out; + } + + if (flags & SYNC_FILE_RANGE_WAIT_AFTER) + ret = file_fdatawait_range(file, offset, endbyte); + +out: + return ret; +} + /* * sys_sync_file_range() permits finely controlled syncing over a segment of * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is @@ -286,77 +357,13 @@ int ksys_sync_file_range(int fd, loff_t offset, loff_t nbytes, { int ret; struct fd f; - struct address_space *mapping; - loff_t endbyte; /* inclusive */ - umode_t i_mode; - - ret = -EINVAL; - if (flags & ~VALID_FLAGS) - goto out; - - endbyte = offset + nbytes; - - if ((s64)offset < 0) - goto out; - if ((s64)endbyte < 0) - goto out; - if (endbyte < offset) - goto out; - - if (sizeof(pgoff_t) == 4) { - if (offset >= (0x100000000ULL << PAGE_SHIFT)) { - /* - * The range starts outside a 32 bit machine's - * pagecache addressing capabilities. Let it "succeed" - */ - ret = 0; - goto out; - } - if (endbyte >= (0x100000000ULL << PAGE_SHIFT)) { - /* - * Out to EOF - */ - nbytes = 0; - } - } - - if (nbytes == 0) - endbyte = LLONG_MAX; - else - endbyte--; /* inclusive */ ret = -EBADF; f = fdget(fd); - if (!f.file) - goto out; + if (f.file) + ret = sync_file_range(f.file, offset, nbytes, flags); - i_mode = file_inode(f.file)->i_mode; - ret = -ESPIPE; - if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) && - !S_ISLNK(i_mode)) - goto out_put; - - mapping = f.file->f_mapping; - ret = 0; - if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) { - ret = file_fdatawait_range(f.file, offset, endbyte); - if (ret < 0) - goto out_put; - } - - if (flags & SYNC_FILE_RANGE_WRITE) { - ret = __filemap_fdatawrite_range(mapping, offset, endbyte, - WB_SYNC_NONE); - if (ret < 0) - goto out_put; - } - - if (flags & SYNC_FILE_RANGE_WAIT_AFTER) - ret = file_fdatawait_range(f.file, offset, endbyte); - -out_put: fdput(f); -out: return ret; } diff --git a/include/linux/fs.h b/include/linux/fs.h index dd28e7679089..2f66e247ecba 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2785,6 +2785,9 @@ extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync); extern int vfs_fsync(struct file *file, int datasync); +extern int sync_file_range(struct file *file, loff_t offset, loff_t nbytes, + unsigned int flags); + /* * Sync the bytes written if this was a synchronous write. Expect ki_pos * to already be updated for the write, and will return either the amount