| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* -*- mode: c; c-basic-offset: 8; -*- |
|---|
| 2 | 3 | * vim: noexpandtab sw=8 ts=8 sts=0: |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * File open, close, extend, truncate |
|---|
| 7 | 8 | * |
|---|
| 8 | 9 | * Copyright (C) 2002, 2004 Oracle. All rights reserved. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or |
|---|
| 11 | | - * modify it under the terms of the GNU General Public |
|---|
| 12 | | - * License as published by the Free Software Foundation; either |
|---|
| 13 | | - * version 2 of the License, or (at your option) any later version. |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 16 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 17 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 18 | | - * General Public License for more details. |
|---|
| 19 | | - * |
|---|
| 20 | | - * You should have received a copy of the GNU General Public |
|---|
| 21 | | - * License along with this program; if not, write to the |
|---|
| 22 | | - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|---|
| 23 | | - * Boston, MA 021110-1307, USA. |
|---|
| 24 | 10 | */ |
|---|
| 25 | 11 | |
|---|
| 26 | 12 | #include <linux/capability.h> |
|---|
| .. | .. |
|---|
| 208 | 194 | needs_barrier = true; |
|---|
| 209 | 195 | err = jbd2_complete_transaction(journal, commit_tid); |
|---|
| 210 | 196 | if (needs_barrier) { |
|---|
| 211 | | - ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); |
|---|
| 197 | + ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL); |
|---|
| 212 | 198 | if (!err) |
|---|
| 213 | 199 | err = ret; |
|---|
| 214 | 200 | } |
|---|
| .. | .. |
|---|
| 724 | 710 | * Thus, we need to explicitly order the zeroed pages. |
|---|
| 725 | 711 | */ |
|---|
| 726 | 712 | static handle_t *ocfs2_zero_start_ordered_transaction(struct inode *inode, |
|---|
| 727 | | - struct buffer_head *di_bh) |
|---|
| 713 | + struct buffer_head *di_bh, |
|---|
| 714 | + loff_t start_byte, |
|---|
| 715 | + loff_t length) |
|---|
| 728 | 716 | { |
|---|
| 729 | 717 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
|---|
| 730 | 718 | handle_t *handle = NULL; |
|---|
| .. | .. |
|---|
| 740 | 728 | goto out; |
|---|
| 741 | 729 | } |
|---|
| 742 | 730 | |
|---|
| 743 | | - ret = ocfs2_jbd2_file_inode(handle, inode); |
|---|
| 731 | + ret = ocfs2_jbd2_inode_add_write(handle, inode, start_byte, length); |
|---|
| 744 | 732 | if (ret < 0) { |
|---|
| 745 | 733 | mlog_errno(ret); |
|---|
| 746 | 734 | goto out; |
|---|
| .. | .. |
|---|
| 779 | 767 | BUG_ON(abs_to > (((u64)index + 1) << PAGE_SHIFT)); |
|---|
| 780 | 768 | BUG_ON(abs_from & (inode->i_blkbits - 1)); |
|---|
| 781 | 769 | |
|---|
| 782 | | - handle = ocfs2_zero_start_ordered_transaction(inode, di_bh); |
|---|
| 770 | + handle = ocfs2_zero_start_ordered_transaction(inode, di_bh, |
|---|
| 771 | + abs_from, |
|---|
| 772 | + abs_to - abs_from); |
|---|
| 783 | 773 | if (IS_ERR(handle)) { |
|---|
| 784 | 774 | ret = PTR_ERR(handle); |
|---|
| 785 | 775 | goto out; |
|---|
| .. | .. |
|---|
| 1244 | 1234 | transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid)); |
|---|
| 1245 | 1235 | if (IS_ERR(transfer_to[USRQUOTA])) { |
|---|
| 1246 | 1236 | status = PTR_ERR(transfer_to[USRQUOTA]); |
|---|
| 1237 | + transfer_to[USRQUOTA] = NULL; |
|---|
| 1247 | 1238 | goto bail_unlock; |
|---|
| 1248 | 1239 | } |
|---|
| 1249 | 1240 | } |
|---|
| .. | .. |
|---|
| 1253 | 1244 | transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid)); |
|---|
| 1254 | 1245 | if (IS_ERR(transfer_to[GRPQUOTA])) { |
|---|
| 1255 | 1246 | status = PTR_ERR(transfer_to[GRPQUOTA]); |
|---|
| 1247 | + transfer_to[GRPQUOTA] = NULL; |
|---|
| 1256 | 1248 | goto bail_unlock; |
|---|
| 1257 | 1249 | } |
|---|
| 1258 | 1250 | } |
|---|
| .. | .. |
|---|
| 2247 | 2239 | struct dentry *dentry = file->f_path.dentry; |
|---|
| 2248 | 2240 | struct inode *inode = d_inode(dentry); |
|---|
| 2249 | 2241 | struct buffer_head *di_bh = NULL; |
|---|
| 2250 | | - loff_t end; |
|---|
| 2251 | 2242 | u32 cpos; |
|---|
| 2252 | 2243 | u32 clusters; |
|---|
| 2253 | 2244 | |
|---|
| .. | .. |
|---|
| 2307 | 2298 | goto out_unlock; |
|---|
| 2308 | 2299 | } |
|---|
| 2309 | 2300 | } |
|---|
| 2310 | | - |
|---|
| 2311 | | - end = pos + count; |
|---|
| 2312 | 2301 | |
|---|
| 2313 | 2302 | ret = ocfs2_check_range_for_refcount(inode, pos, count); |
|---|
| 2314 | 2303 | if (ret == 1) { |
|---|
| .. | .. |
|---|
| 2645 | 2634 | return offset; |
|---|
| 2646 | 2635 | } |
|---|
| 2647 | 2636 | |
|---|
| 2648 | | -static int ocfs2_file_clone_range(struct file *file_in, |
|---|
| 2649 | | - loff_t pos_in, |
|---|
| 2650 | | - struct file *file_out, |
|---|
| 2651 | | - loff_t pos_out, |
|---|
| 2652 | | - u64 len) |
|---|
| 2637 | +static loff_t ocfs2_remap_file_range(struct file *file_in, loff_t pos_in, |
|---|
| 2638 | + struct file *file_out, loff_t pos_out, |
|---|
| 2639 | + loff_t len, unsigned int remap_flags) |
|---|
| 2653 | 2640 | { |
|---|
| 2654 | | - return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out, |
|---|
| 2655 | | - len, false); |
|---|
| 2656 | | -} |
|---|
| 2641 | + struct inode *inode_in = file_inode(file_in); |
|---|
| 2642 | + struct inode *inode_out = file_inode(file_out); |
|---|
| 2643 | + struct ocfs2_super *osb = OCFS2_SB(inode_in->i_sb); |
|---|
| 2644 | + struct buffer_head *in_bh = NULL, *out_bh = NULL; |
|---|
| 2645 | + bool same_inode = (inode_in == inode_out); |
|---|
| 2646 | + loff_t remapped = 0; |
|---|
| 2647 | + ssize_t ret; |
|---|
| 2657 | 2648 | |
|---|
| 2658 | | -static int ocfs2_file_dedupe_range(struct file *file_in, |
|---|
| 2659 | | - loff_t pos_in, |
|---|
| 2660 | | - struct file *file_out, |
|---|
| 2661 | | - loff_t pos_out, |
|---|
| 2662 | | - u64 len) |
|---|
| 2663 | | -{ |
|---|
| 2664 | | - return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out, |
|---|
| 2665 | | - len, true); |
|---|
| 2649 | + if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) |
|---|
| 2650 | + return -EINVAL; |
|---|
| 2651 | + if (!ocfs2_refcount_tree(osb)) |
|---|
| 2652 | + return -EOPNOTSUPP; |
|---|
| 2653 | + if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) |
|---|
| 2654 | + return -EROFS; |
|---|
| 2655 | + |
|---|
| 2656 | + /* Lock both files against IO */ |
|---|
| 2657 | + ret = ocfs2_reflink_inodes_lock(inode_in, &in_bh, inode_out, &out_bh); |
|---|
| 2658 | + if (ret) |
|---|
| 2659 | + return ret; |
|---|
| 2660 | + |
|---|
| 2661 | + /* Check file eligibility and prepare for block sharing. */ |
|---|
| 2662 | + ret = -EINVAL; |
|---|
| 2663 | + if ((OCFS2_I(inode_in)->ip_flags & OCFS2_INODE_SYSTEM_FILE) || |
|---|
| 2664 | + (OCFS2_I(inode_out)->ip_flags & OCFS2_INODE_SYSTEM_FILE)) |
|---|
| 2665 | + goto out_unlock; |
|---|
| 2666 | + |
|---|
| 2667 | + ret = generic_remap_file_range_prep(file_in, pos_in, file_out, pos_out, |
|---|
| 2668 | + &len, remap_flags); |
|---|
| 2669 | + if (ret < 0 || len == 0) |
|---|
| 2670 | + goto out_unlock; |
|---|
| 2671 | + |
|---|
| 2672 | + /* Lock out changes to the allocation maps and remap. */ |
|---|
| 2673 | + down_write(&OCFS2_I(inode_in)->ip_alloc_sem); |
|---|
| 2674 | + if (!same_inode) |
|---|
| 2675 | + down_write_nested(&OCFS2_I(inode_out)->ip_alloc_sem, |
|---|
| 2676 | + SINGLE_DEPTH_NESTING); |
|---|
| 2677 | + |
|---|
| 2678 | + /* Zap any page cache for the destination file's range. */ |
|---|
| 2679 | + truncate_inode_pages_range(&inode_out->i_data, |
|---|
| 2680 | + round_down(pos_out, PAGE_SIZE), |
|---|
| 2681 | + round_up(pos_out + len, PAGE_SIZE) - 1); |
|---|
| 2682 | + |
|---|
| 2683 | + remapped = ocfs2_reflink_remap_blocks(inode_in, in_bh, pos_in, |
|---|
| 2684 | + inode_out, out_bh, pos_out, len); |
|---|
| 2685 | + up_write(&OCFS2_I(inode_in)->ip_alloc_sem); |
|---|
| 2686 | + if (!same_inode) |
|---|
| 2687 | + up_write(&OCFS2_I(inode_out)->ip_alloc_sem); |
|---|
| 2688 | + if (remapped < 0) { |
|---|
| 2689 | + ret = remapped; |
|---|
| 2690 | + mlog_errno(ret); |
|---|
| 2691 | + goto out_unlock; |
|---|
| 2692 | + } |
|---|
| 2693 | + |
|---|
| 2694 | + /* |
|---|
| 2695 | + * Empty the extent map so that we may get the right extent |
|---|
| 2696 | + * record from the disk. |
|---|
| 2697 | + */ |
|---|
| 2698 | + ocfs2_extent_map_trunc(inode_in, 0); |
|---|
| 2699 | + ocfs2_extent_map_trunc(inode_out, 0); |
|---|
| 2700 | + |
|---|
| 2701 | + ret = ocfs2_reflink_update_dest(inode_out, out_bh, pos_out + len); |
|---|
| 2702 | + if (ret) { |
|---|
| 2703 | + mlog_errno(ret); |
|---|
| 2704 | + goto out_unlock; |
|---|
| 2705 | + } |
|---|
| 2706 | + |
|---|
| 2707 | +out_unlock: |
|---|
| 2708 | + ocfs2_reflink_inodes_unlock(inode_in, in_bh, inode_out, out_bh); |
|---|
| 2709 | + return remapped > 0 ? remapped : ret; |
|---|
| 2666 | 2710 | } |
|---|
| 2667 | 2711 | |
|---|
| 2668 | 2712 | const struct inode_operations ocfs2_file_iops = { |
|---|
| .. | .. |
|---|
| 2704 | 2748 | .splice_read = generic_file_splice_read, |
|---|
| 2705 | 2749 | .splice_write = iter_file_splice_write, |
|---|
| 2706 | 2750 | .fallocate = ocfs2_fallocate, |
|---|
| 2707 | | - .clone_file_range = ocfs2_file_clone_range, |
|---|
| 2708 | | - .dedupe_file_range = ocfs2_file_dedupe_range, |
|---|
| 2751 | + .remap_file_range = ocfs2_remap_file_range, |
|---|
| 2709 | 2752 | }; |
|---|
| 2710 | 2753 | |
|---|
| 2711 | 2754 | const struct file_operations ocfs2_dops = { |
|---|
| .. | .. |
|---|
| 2751 | 2794 | .splice_read = generic_file_splice_read, |
|---|
| 2752 | 2795 | .splice_write = iter_file_splice_write, |
|---|
| 2753 | 2796 | .fallocate = ocfs2_fallocate, |
|---|
| 2754 | | - .clone_file_range = ocfs2_file_clone_range, |
|---|
| 2755 | | - .dedupe_file_range = ocfs2_file_dedupe_range, |
|---|
| 2797 | + .remap_file_range = ocfs2_remap_file_range, |
|---|
| 2756 | 2798 | }; |
|---|
| 2757 | 2799 | |
|---|
| 2758 | 2800 | const struct file_operations ocfs2_dops_no_plocks = { |
|---|