diff options
author | Luis Henriques <lhenriques@suse.com> | 2019-10-31 07:49:39 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2019-11-05 09:42:58 -0500 |
commit | a3a0819388b2bf15e7eafe38ff6aacfc27b12df0 (patch) | |
tree | 16e134b5e219b5d17bfae211d92a16ca269b2e23 | |
parent | 5bb5e6ee6f5c557dcd19822eccd7bcced1e1a410 (diff) |
ceph: don't allow copy_file_range when stripe_count != 1
copy_file_range tries to use the OSD 'copy-from' operation, which simply
performs a full object copy. Unfortunately, the implementation of this
system call assumes that stripe_count is always set to 1 and doesn't take
into account that the data may be striped across an object set. If the
file layout has stripe_count different from 1, then the destination file
data will be corrupted.
For example:
Consider a 8 MiB file with 4 MiB object size, stripe_count of 2 and
stripe_size of 2 MiB; the first half of the file will be filled with 'A's
and the second half will be filled with 'B's:
0 4M 8M Obj1 Obj2
+------+------+ +----+ +----+
file: | AAAA | BBBB | | AA | | AA |
+------+------+ |----| |----|
| BB | | BB |
+----+ +----+
If we copy_file_range this file into a new file (which needs to have the
same file layout!), then it will start by copying the object starting at
file offset 0 (Obj1). And then it will copy the object starting at file
offset 4M -- which is Obj1 again.
Unfortunately, the solution for this is to not allow remote object copies
to be performed when the file layout stripe_count is not 1 and simply
fallback to the default (VFS) copy_file_range implementation.
Cc: stable@vger.kernel.org
Signed-off-by: Luis Henriques <lhenriques@suse.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r-- | fs/ceph/file.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index d2854cd2f4f5..bd77adb64bfd 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -1959,10 +1959,18 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off, | |||
1959 | if (ceph_test_mount_opt(src_fsc, NOCOPYFROM)) | 1959 | if (ceph_test_mount_opt(src_fsc, NOCOPYFROM)) |
1960 | return -EOPNOTSUPP; | 1960 | return -EOPNOTSUPP; |
1961 | 1961 | ||
1962 | /* | ||
1963 | * Striped file layouts require that we copy partial objects, but the | ||
1964 | * OSD copy-from operation only supports full-object copies. Limit | ||
1965 | * this to non-striped file layouts for now. | ||
1966 | */ | ||
1962 | if ((src_ci->i_layout.stripe_unit != dst_ci->i_layout.stripe_unit) || | 1967 | if ((src_ci->i_layout.stripe_unit != dst_ci->i_layout.stripe_unit) || |
1963 | (src_ci->i_layout.stripe_count != dst_ci->i_layout.stripe_count) || | 1968 | (src_ci->i_layout.stripe_count != 1) || |
1964 | (src_ci->i_layout.object_size != dst_ci->i_layout.object_size)) | 1969 | (dst_ci->i_layout.stripe_count != 1) || |
1970 | (src_ci->i_layout.object_size != dst_ci->i_layout.object_size)) { | ||
1971 | dout("Invalid src/dst files layout\n"); | ||
1965 | return -EOPNOTSUPP; | 1972 | return -EOPNOTSUPP; |
1973 | } | ||
1966 | 1974 | ||
1967 | if (len < src_ci->i_layout.object_size) | 1975 | if (len < src_ci->i_layout.object_size) |
1968 | return -EOPNOTSUPP; /* no remote copy will be done */ | 1976 | return -EOPNOTSUPP; /* no remote copy will be done */ |