| .. | .. |
|---|
| 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 | } |
|---|
| .. | .. |
|---|
| 2002 | 1994 | } |
|---|
| 2003 | 1995 | } |
|---|
| 2004 | 1996 | |
|---|
| 2005 | | - if (file && should_remove_suid(file->f_path.dentry)) { |
|---|
| 1997 | + if (file && setattr_should_drop_suidgid(file_inode(file))) { |
|---|
| 2006 | 1998 | ret = __ocfs2_write_remove_suid(inode, di_bh); |
|---|
| 2007 | 1999 | if (ret) { |
|---|
| 2008 | 2000 | mlog_errno(ret); |
|---|
| .. | .. |
|---|
| 2111 | 2103 | struct ocfs2_space_resv sr; |
|---|
| 2112 | 2104 | int change_size = 1; |
|---|
| 2113 | 2105 | int cmd = OCFS2_IOC_RESVSP64; |
|---|
| 2106 | + int ret = 0; |
|---|
| 2114 | 2107 | |
|---|
| 2115 | 2108 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) |
|---|
| 2116 | 2109 | return -EOPNOTSUPP; |
|---|
| 2117 | 2110 | if (!ocfs2_writes_unwritten_extents(osb)) |
|---|
| 2118 | 2111 | return -EOPNOTSUPP; |
|---|
| 2119 | 2112 | |
|---|
| 2120 | | - if (mode & FALLOC_FL_KEEP_SIZE) |
|---|
| 2113 | + if (mode & FALLOC_FL_KEEP_SIZE) { |
|---|
| 2121 | 2114 | change_size = 0; |
|---|
| 2115 | + } else { |
|---|
| 2116 | + ret = inode_newsize_ok(inode, offset + len); |
|---|
| 2117 | + if (ret) |
|---|
| 2118 | + return ret; |
|---|
| 2119 | + } |
|---|
| 2122 | 2120 | |
|---|
| 2123 | 2121 | if (mode & FALLOC_FL_PUNCH_HOLE) |
|---|
| 2124 | 2122 | cmd = OCFS2_IOC_UNRESVSP64; |
|---|
| .. | .. |
|---|
| 2247 | 2245 | struct dentry *dentry = file->f_path.dentry; |
|---|
| 2248 | 2246 | struct inode *inode = d_inode(dentry); |
|---|
| 2249 | 2247 | struct buffer_head *di_bh = NULL; |
|---|
| 2250 | | - loff_t end; |
|---|
| 2251 | 2248 | u32 cpos; |
|---|
| 2252 | 2249 | u32 clusters; |
|---|
| 2253 | 2250 | |
|---|
| .. | .. |
|---|
| 2291 | 2288 | * inode. There's also the dinode i_size state which |
|---|
| 2292 | 2289 | * can be lost via setattr during extending writes (we |
|---|
| 2293 | 2290 | * set inode->i_size at the end of a write. */ |
|---|
| 2294 | | - if (should_remove_suid(dentry)) { |
|---|
| 2291 | + if (setattr_should_drop_suidgid(inode)) { |
|---|
| 2295 | 2292 | if (meta_level == 0) { |
|---|
| 2296 | 2293 | ocfs2_inode_unlock_for_extent_tree(inode, |
|---|
| 2297 | 2294 | &di_bh, |
|---|
| .. | .. |
|---|
| 2307 | 2304 | goto out_unlock; |
|---|
| 2308 | 2305 | } |
|---|
| 2309 | 2306 | } |
|---|
| 2310 | | - |
|---|
| 2311 | | - end = pos + count; |
|---|
| 2312 | 2307 | |
|---|
| 2313 | 2308 | ret = ocfs2_check_range_for_refcount(inode, pos, count); |
|---|
| 2314 | 2309 | if (ret == 1) { |
|---|
| .. | .. |
|---|
| 2645 | 2640 | return offset; |
|---|
| 2646 | 2641 | } |
|---|
| 2647 | 2642 | |
|---|
| 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) |
|---|
| 2643 | +static loff_t ocfs2_remap_file_range(struct file *file_in, loff_t pos_in, |
|---|
| 2644 | + struct file *file_out, loff_t pos_out, |
|---|
| 2645 | + loff_t len, unsigned int remap_flags) |
|---|
| 2653 | 2646 | { |
|---|
| 2654 | | - return ocfs2_reflink_remap_range(file_in, pos_in, file_out, pos_out, |
|---|
| 2655 | | - len, false); |
|---|
| 2656 | | -} |
|---|
| 2647 | + struct inode *inode_in = file_inode(file_in); |
|---|
| 2648 | + struct inode *inode_out = file_inode(file_out); |
|---|
| 2649 | + struct ocfs2_super *osb = OCFS2_SB(inode_in->i_sb); |
|---|
| 2650 | + struct buffer_head *in_bh = NULL, *out_bh = NULL; |
|---|
| 2651 | + bool same_inode = (inode_in == inode_out); |
|---|
| 2652 | + loff_t remapped = 0; |
|---|
| 2653 | + ssize_t ret; |
|---|
| 2657 | 2654 | |
|---|
| 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); |
|---|
| 2655 | + if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) |
|---|
| 2656 | + return -EINVAL; |
|---|
| 2657 | + if (!ocfs2_refcount_tree(osb)) |
|---|
| 2658 | + return -EOPNOTSUPP; |
|---|
| 2659 | + if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) |
|---|
| 2660 | + return -EROFS; |
|---|
| 2661 | + |
|---|
| 2662 | + /* Lock both files against IO */ |
|---|
| 2663 | + ret = ocfs2_reflink_inodes_lock(inode_in, &in_bh, inode_out, &out_bh); |
|---|
| 2664 | + if (ret) |
|---|
| 2665 | + return ret; |
|---|
| 2666 | + |
|---|
| 2667 | + /* Check file eligibility and prepare for block sharing. */ |
|---|
| 2668 | + ret = -EINVAL; |
|---|
| 2669 | + if ((OCFS2_I(inode_in)->ip_flags & OCFS2_INODE_SYSTEM_FILE) || |
|---|
| 2670 | + (OCFS2_I(inode_out)->ip_flags & OCFS2_INODE_SYSTEM_FILE)) |
|---|
| 2671 | + goto out_unlock; |
|---|
| 2672 | + |
|---|
| 2673 | + ret = generic_remap_file_range_prep(file_in, pos_in, file_out, pos_out, |
|---|
| 2674 | + &len, remap_flags); |
|---|
| 2675 | + if (ret < 0 || len == 0) |
|---|
| 2676 | + goto out_unlock; |
|---|
| 2677 | + |
|---|
| 2678 | + /* Lock out changes to the allocation maps and remap. */ |
|---|
| 2679 | + down_write(&OCFS2_I(inode_in)->ip_alloc_sem); |
|---|
| 2680 | + if (!same_inode) |
|---|
| 2681 | + down_write_nested(&OCFS2_I(inode_out)->ip_alloc_sem, |
|---|
| 2682 | + SINGLE_DEPTH_NESTING); |
|---|
| 2683 | + |
|---|
| 2684 | + /* Zap any page cache for the destination file's range. */ |
|---|
| 2685 | + truncate_inode_pages_range(&inode_out->i_data, |
|---|
| 2686 | + round_down(pos_out, PAGE_SIZE), |
|---|
| 2687 | + round_up(pos_out + len, PAGE_SIZE) - 1); |
|---|
| 2688 | + |
|---|
| 2689 | + remapped = ocfs2_reflink_remap_blocks(inode_in, in_bh, pos_in, |
|---|
| 2690 | + inode_out, out_bh, pos_out, len); |
|---|
| 2691 | + up_write(&OCFS2_I(inode_in)->ip_alloc_sem); |
|---|
| 2692 | + if (!same_inode) |
|---|
| 2693 | + up_write(&OCFS2_I(inode_out)->ip_alloc_sem); |
|---|
| 2694 | + if (remapped < 0) { |
|---|
| 2695 | + ret = remapped; |
|---|
| 2696 | + mlog_errno(ret); |
|---|
| 2697 | + goto out_unlock; |
|---|
| 2698 | + } |
|---|
| 2699 | + |
|---|
| 2700 | + /* |
|---|
| 2701 | + * Empty the extent map so that we may get the right extent |
|---|
| 2702 | + * record from the disk. |
|---|
| 2703 | + */ |
|---|
| 2704 | + ocfs2_extent_map_trunc(inode_in, 0); |
|---|
| 2705 | + ocfs2_extent_map_trunc(inode_out, 0); |
|---|
| 2706 | + |
|---|
| 2707 | + ret = ocfs2_reflink_update_dest(inode_out, out_bh, pos_out + len); |
|---|
| 2708 | + if (ret) { |
|---|
| 2709 | + mlog_errno(ret); |
|---|
| 2710 | + goto out_unlock; |
|---|
| 2711 | + } |
|---|
| 2712 | + |
|---|
| 2713 | +out_unlock: |
|---|
| 2714 | + ocfs2_reflink_inodes_unlock(inode_in, in_bh, inode_out, out_bh); |
|---|
| 2715 | + return remapped > 0 ? remapped : ret; |
|---|
| 2666 | 2716 | } |
|---|
| 2667 | 2717 | |
|---|
| 2668 | 2718 | const struct inode_operations ocfs2_file_iops = { |
|---|
| .. | .. |
|---|
| 2704 | 2754 | .splice_read = generic_file_splice_read, |
|---|
| 2705 | 2755 | .splice_write = iter_file_splice_write, |
|---|
| 2706 | 2756 | .fallocate = ocfs2_fallocate, |
|---|
| 2707 | | - .clone_file_range = ocfs2_file_clone_range, |
|---|
| 2708 | | - .dedupe_file_range = ocfs2_file_dedupe_range, |
|---|
| 2757 | + .remap_file_range = ocfs2_remap_file_range, |
|---|
| 2709 | 2758 | }; |
|---|
| 2710 | 2759 | |
|---|
| 2711 | 2760 | const struct file_operations ocfs2_dops = { |
|---|
| .. | .. |
|---|
| 2751 | 2800 | .splice_read = generic_file_splice_read, |
|---|
| 2752 | 2801 | .splice_write = iter_file_splice_write, |
|---|
| 2753 | 2802 | .fallocate = ocfs2_fallocate, |
|---|
| 2754 | | - .clone_file_range = ocfs2_file_clone_range, |
|---|
| 2755 | | - .dedupe_file_range = ocfs2_file_dedupe_range, |
|---|
| 2803 | + .remap_file_range = ocfs2_remap_file_range, |
|---|
| 2756 | 2804 | }; |
|---|
| 2757 | 2805 | |
|---|
| 2758 | 2806 | const struct file_operations ocfs2_dops_no_plocks = { |
|---|