aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_reflink.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-17 21:44:00 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-17 21:44:00 -0500
commit0110c350c86d511be2130cb2a30dcbb76c4af750 (patch)
treed343a9e0fcb586a7110b13d411b314d33d404c08 /fs/xfs/xfs_reflink.c
parentd9cb5bfcc3339f1a63df8fe0af8cece33c83c3af (diff)
parent9763f7a4a5f7b1a7c480fa06d01b2bad25163c0a (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull more vfs updates from Al Viro: "In this pile: - autofs-namespace series - dedupe stuff - more struct path constification" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (40 commits) ocfs2: implement the VFS clone_range, copy_range, and dedupe_range features ocfs2: charge quota for reflinked blocks ocfs2: fix bad pointer cast ocfs2: always unlock when completing dio writes ocfs2: don't eat io errors during _dio_end_io_write ocfs2: budget for extent tree splits when adding refcount flag ocfs2: prohibit refcounted swapfiles ocfs2: add newlines to some error messages ocfs2: convert inode refcount test to a helper simple_write_end(): don't zero in short copy into uptodate exofs: don't mess with simple_write_{begin,end} 9p: saner ->write_end() on failing copy into non-uptodate page fix gfs2_stuffed_write_end() on short copies fix ceph_write_end() nfs_write_end(): fix handling of short copies vfs: refactor clone/dedupe_file_range common functions fs: try to clone files first in vfs_copy_file_range vfs: misc struct path constification namespace.c: constify struct path passed to a bunch of primitives quota: constify struct path in quota_on ...
Diffstat (limited to 'fs/xfs/xfs_reflink.c')
-rw-r--r--fs/xfs/xfs_reflink.c219
1 files changed, 9 insertions, 210 deletions
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 88fd03c66e99..aca2d4bd4303 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -1114,111 +1114,6 @@ err:
1114} 1114}
1115 1115
1116/* 1116/*
1117 * Read a page's worth of file data into the page cache. Return the page
1118 * locked.
1119 */
1120static struct page *
1121xfs_get_page(
1122 struct inode *inode,
1123 xfs_off_t offset)
1124{
1125 struct address_space *mapping;
1126 struct page *page;
1127 pgoff_t n;
1128
1129 n = offset >> PAGE_SHIFT;
1130 mapping = inode->i_mapping;
1131 page = read_mapping_page(mapping, n, NULL);
1132 if (IS_ERR(page))
1133 return page;
1134 if (!PageUptodate(page)) {
1135 put_page(page);
1136 return ERR_PTR(-EIO);
1137 }
1138 lock_page(page);
1139 return page;
1140}
1141
1142/*
1143 * Compare extents of two files to see if they are the same.
1144 */
1145static int
1146xfs_compare_extents(
1147 struct inode *src,
1148 xfs_off_t srcoff,
1149 struct inode *dest,
1150 xfs_off_t destoff,
1151 xfs_off_t len,
1152 bool *is_same)
1153{
1154 xfs_off_t src_poff;
1155 xfs_off_t dest_poff;
1156 void *src_addr;
1157 void *dest_addr;
1158 struct page *src_page;
1159 struct page *dest_page;
1160 xfs_off_t cmp_len;
1161 bool same;
1162 int error;
1163
1164 error = -EINVAL;
1165 same = true;
1166 while (len) {
1167 src_poff = srcoff & (PAGE_SIZE - 1);
1168 dest_poff = destoff & (PAGE_SIZE - 1);
1169 cmp_len = min(PAGE_SIZE - src_poff,
1170 PAGE_SIZE - dest_poff);
1171 cmp_len = min(cmp_len, len);
1172 ASSERT(cmp_len > 0);
1173
1174 trace_xfs_reflink_compare_extents(XFS_I(src), srcoff, cmp_len,
1175 XFS_I(dest), destoff);
1176
1177 src_page = xfs_get_page(src, srcoff);
1178 if (IS_ERR(src_page)) {
1179 error = PTR_ERR(src_page);
1180 goto out_error;
1181 }
1182 dest_page = xfs_get_page(dest, destoff);
1183 if (IS_ERR(dest_page)) {
1184 error = PTR_ERR(dest_page);
1185 unlock_page(src_page);
1186 put_page(src_page);
1187 goto out_error;
1188 }
1189 src_addr = kmap_atomic(src_page);
1190 dest_addr = kmap_atomic(dest_page);
1191
1192 flush_dcache_page(src_page);
1193 flush_dcache_page(dest_page);
1194
1195 if (memcmp(src_addr + src_poff, dest_addr + dest_poff, cmp_len))
1196 same = false;
1197
1198 kunmap_atomic(dest_addr);
1199 kunmap_atomic(src_addr);
1200 unlock_page(dest_page);
1201 unlock_page(src_page);
1202 put_page(dest_page);
1203 put_page(src_page);
1204
1205 if (!same)
1206 break;
1207
1208 srcoff += cmp_len;
1209 destoff += cmp_len;
1210 len -= cmp_len;
1211 }
1212
1213 *is_same = same;
1214 return 0;
1215
1216out_error:
1217 trace_xfs_reflink_compare_extents_error(XFS_I(dest), error, _RET_IP_);
1218 return error;
1219}
1220
1221/*
1222 * Link a range of blocks from one file to another. 1117 * Link a range of blocks from one file to another.
1223 */ 1118 */
1224int 1119int
@@ -1235,14 +1130,11 @@ xfs_reflink_remap_range(
1235 struct inode *inode_out = file_inode(file_out); 1130 struct inode *inode_out = file_inode(file_out);
1236 struct xfs_inode *dest = XFS_I(inode_out); 1131 struct xfs_inode *dest = XFS_I(inode_out);
1237 struct xfs_mount *mp = src->i_mount; 1132 struct xfs_mount *mp = src->i_mount;
1238 loff_t bs = inode_out->i_sb->s_blocksize;
1239 bool same_inode = (inode_in == inode_out); 1133 bool same_inode = (inode_in == inode_out);
1240 xfs_fileoff_t sfsbno, dfsbno; 1134 xfs_fileoff_t sfsbno, dfsbno;
1241 xfs_filblks_t fsblen; 1135 xfs_filblks_t fsblen;
1242 xfs_extlen_t cowextsize; 1136 xfs_extlen_t cowextsize;
1243 loff_t isize;
1244 ssize_t ret; 1137 ssize_t ret;
1245 loff_t blen;
1246 1138
1247 if (!xfs_sb_version_hasreflink(&mp->m_sb)) 1139 if (!xfs_sb_version_hasreflink(&mp->m_sb))
1248 return -EOPNOTSUPP; 1140 return -EOPNOTSUPP;
@@ -1257,26 +1149,8 @@ xfs_reflink_remap_range(
1257 else 1149 else
1258 xfs_lock_two_inodes(src, dest, XFS_MMAPLOCK_EXCL); 1150 xfs_lock_two_inodes(src, dest, XFS_MMAPLOCK_EXCL);
1259 1151
1260 /* Don't touch certain kinds of inodes */ 1152 /* Check file eligibility and prepare for block sharing. */
1261 ret = -EPERM;
1262 if (IS_IMMUTABLE(inode_out))
1263 goto out_unlock;
1264
1265 ret = -ETXTBSY;
1266 if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
1267 goto out_unlock;
1268
1269
1270 /* Don't reflink dirs, pipes, sockets... */
1271 ret = -EISDIR;
1272 if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
1273 goto out_unlock;
1274 ret = -EINVAL; 1153 ret = -EINVAL;
1275 if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode))
1276 goto out_unlock;
1277 if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
1278 goto out_unlock;
1279
1280 /* Don't reflink realtime inodes */ 1154 /* Don't reflink realtime inodes */
1281 if (XFS_IS_REALTIME_INODE(src) || XFS_IS_REALTIME_INODE(dest)) 1155 if (XFS_IS_REALTIME_INODE(src) || XFS_IS_REALTIME_INODE(dest))
1282 goto out_unlock; 1156 goto out_unlock;
@@ -1285,97 +1159,18 @@ xfs_reflink_remap_range(
1285 if (IS_DAX(inode_in) || IS_DAX(inode_out)) 1159 if (IS_DAX(inode_in) || IS_DAX(inode_out))
1286 goto out_unlock; 1160 goto out_unlock;
1287 1161
1288 /* Are we going all the way to the end? */ 1162 ret = vfs_clone_file_prep_inodes(inode_in, pos_in, inode_out, pos_out,
1289 isize = i_size_read(inode_in); 1163 &len, is_dedupe);
1290 if (isize == 0) { 1164 if (ret || len == 0)
1291 ret = 0;
1292 goto out_unlock;
1293 }
1294
1295 /* Zero length dedupe exits immediately; reflink goes to EOF. */
1296 if (len == 0) {
1297 if (is_dedupe) {
1298 ret = 0;
1299 goto out_unlock;
1300 }
1301 len = isize - pos_in;
1302 }
1303
1304 /* Ensure offsets don't wrap and the input is inside i_size */
1305 if (pos_in + len < pos_in || pos_out + len < pos_out ||
1306 pos_in + len > isize)
1307 goto out_unlock;
1308
1309 /* Don't allow dedupe past EOF in the dest file */
1310 if (is_dedupe) {
1311 loff_t disize;
1312
1313 disize = i_size_read(inode_out);
1314 if (pos_out >= disize || pos_out + len > disize)
1315 goto out_unlock;
1316 }
1317
1318 /* If we're linking to EOF, continue to the block boundary. */
1319 if (pos_in + len == isize)
1320 blen = ALIGN(isize, bs) - pos_in;
1321 else
1322 blen = len;
1323
1324 /* Only reflink if we're aligned to block boundaries */
1325 if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) ||
1326 !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs))
1327 goto out_unlock;
1328
1329 /* Don't allow overlapped reflink within the same file */
1330 if (same_inode) {
1331 if (pos_out + blen > pos_in && pos_out < pos_in + blen)
1332 goto out_unlock;
1333 }
1334
1335 /* Wait for the completion of any pending IOs on both files */
1336 inode_dio_wait(inode_in);
1337 if (!same_inode)
1338 inode_dio_wait(inode_out);
1339
1340 ret = filemap_write_and_wait_range(inode_in->i_mapping,
1341 pos_in, pos_in + len - 1);
1342 if (ret)
1343 goto out_unlock;
1344
1345 ret = filemap_write_and_wait_range(inode_out->i_mapping,
1346 pos_out, pos_out + len - 1);
1347 if (ret)
1348 goto out_unlock; 1165 goto out_unlock;
1349 1166
1350 trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out); 1167 trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out);
1351 1168
1352 /* 1169 /* Set flags and remap blocks. */
1353 * Check that the extents are the same.
1354 */
1355 if (is_dedupe) {
1356 bool is_same = false;
1357
1358 ret = xfs_compare_extents(inode_in, pos_in, inode_out, pos_out,
1359 len, &is_same);
1360 if (ret)
1361 goto out_unlock;
1362 if (!is_same) {
1363 ret = -EBADE;
1364 goto out_unlock;
1365 }
1366 }
1367
1368 ret = xfs_reflink_set_inode_flag(src, dest); 1170 ret = xfs_reflink_set_inode_flag(src, dest);
1369 if (ret) 1171 if (ret)
1370 goto out_unlock; 1172 goto out_unlock;
1371 1173
1372 /*
1373 * Invalidate the page cache so that we can clear any CoW mappings
1374 * in the destination file.
1375 */
1376 truncate_inode_pages_range(&inode_out->i_data, pos_out,
1377 PAGE_ALIGN(pos_out + len) - 1);
1378
1379 dfsbno = XFS_B_TO_FSBT(mp, pos_out); 1174 dfsbno = XFS_B_TO_FSBT(mp, pos_out);
1380 sfsbno = XFS_B_TO_FSBT(mp, pos_in); 1175 sfsbno = XFS_B_TO_FSBT(mp, pos_in);
1381 fsblen = XFS_B_TO_FSB(mp, len); 1176 fsblen = XFS_B_TO_FSB(mp, len);
@@ -1384,6 +1179,10 @@ xfs_reflink_remap_range(
1384 if (ret) 1179 if (ret)
1385 goto out_unlock; 1180 goto out_unlock;
1386 1181
1182 /* Zap any page cache for the destination file's range. */
1183 truncate_inode_pages_range(&inode_out->i_data, pos_out,
1184 PAGE_ALIGN(pos_out + len) - 1);
1185
1387 /* 1186 /*
1388 * Carry the cowextsize hint from src to dest if we're sharing the 1187 * Carry the cowextsize hint from src to dest if we're sharing the
1389 * entire source file to the entire destination file, the source file 1188 * entire source file to the entire destination file, the source file