diff options
Diffstat (limited to 'fs/ocfs2/file.c')
-rw-r--r-- | fs/ocfs2/file.c | 99 |
1 files changed, 93 insertions, 6 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 781ba6c4ef85..a62b14eb4065 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -397,6 +397,15 @@ static int ocfs2_truncate_file(struct inode *inode, | |||
397 | unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1); | 397 | unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1); |
398 | truncate_inode_pages(inode->i_mapping, new_i_size); | 398 | truncate_inode_pages(inode->i_mapping, new_i_size); |
399 | 399 | ||
400 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
401 | status = ocfs2_truncate_inline(inode, di_bh, new_i_size, | ||
402 | i_size_read(inode), 0); | ||
403 | if (status) | ||
404 | mlog_errno(status); | ||
405 | |||
406 | goto bail_unlock_data; | ||
407 | } | ||
408 | |||
400 | /* alright, we're going to need to do a full blown alloc size | 409 | /* alright, we're going to need to do a full blown alloc size |
401 | * change. Orphan the inode so that recovery can complete the | 410 | * change. Orphan the inode so that recovery can complete the |
402 | * truncate if necessary. This does the task of marking | 411 | * truncate if necessary. This does the task of marking |
@@ -908,7 +917,8 @@ static int ocfs2_extend_file(struct inode *inode, | |||
908 | struct buffer_head *di_bh, | 917 | struct buffer_head *di_bh, |
909 | u64 new_i_size) | 918 | u64 new_i_size) |
910 | { | 919 | { |
911 | int ret = 0; | 920 | int ret = 0, data_locked = 0; |
921 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
912 | 922 | ||
913 | BUG_ON(!di_bh); | 923 | BUG_ON(!di_bh); |
914 | 924 | ||
@@ -920,7 +930,17 @@ static int ocfs2_extend_file(struct inode *inode, | |||
920 | goto out; | 930 | goto out; |
921 | BUG_ON(new_i_size < i_size_read(inode)); | 931 | BUG_ON(new_i_size < i_size_read(inode)); |
922 | 932 | ||
923 | if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) | 933 | /* |
934 | * Fall through for converting inline data, even if the fs | ||
935 | * supports sparse files. | ||
936 | * | ||
937 | * The check for inline data here is legal - nobody can add | ||
938 | * the feature since we have i_mutex. We must check it again | ||
939 | * after acquiring ip_alloc_sem though, as paths like mmap | ||
940 | * might have raced us to converting the inode to extents. | ||
941 | */ | ||
942 | if (!(oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) | ||
943 | && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) | ||
924 | goto out_update_size; | 944 | goto out_update_size; |
925 | 945 | ||
926 | /* | 946 | /* |
@@ -935,6 +955,7 @@ static int ocfs2_extend_file(struct inode *inode, | |||
935 | mlog_errno(ret); | 955 | mlog_errno(ret); |
936 | goto out; | 956 | goto out; |
937 | } | 957 | } |
958 | data_locked = 1; | ||
938 | 959 | ||
939 | /* | 960 | /* |
940 | * The alloc sem blocks people in read/write from reading our | 961 | * The alloc sem blocks people in read/write from reading our |
@@ -942,9 +963,31 @@ static int ocfs2_extend_file(struct inode *inode, | |||
942 | * i_mutex to block other extend/truncate calls while we're | 963 | * i_mutex to block other extend/truncate calls while we're |
943 | * here. | 964 | * here. |
944 | */ | 965 | */ |
945 | down_write(&OCFS2_I(inode)->ip_alloc_sem); | 966 | down_write(&oi->ip_alloc_sem); |
946 | ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size); | 967 | |
947 | up_write(&OCFS2_I(inode)->ip_alloc_sem); | 968 | if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) { |
969 | /* | ||
970 | * We can optimize small extends by keeping the inodes | ||
971 | * inline data. | ||
972 | */ | ||
973 | if (ocfs2_size_fits_inline_data(di_bh, new_i_size)) { | ||
974 | up_write(&oi->ip_alloc_sem); | ||
975 | goto out_update_size; | ||
976 | } | ||
977 | |||
978 | ret = ocfs2_convert_inline_data_to_extents(inode, di_bh); | ||
979 | if (ret) { | ||
980 | up_write(&oi->ip_alloc_sem); | ||
981 | |||
982 | mlog_errno(ret); | ||
983 | goto out_unlock; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) | ||
988 | ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size); | ||
989 | |||
990 | up_write(&oi->ip_alloc_sem); | ||
948 | 991 | ||
949 | if (ret < 0) { | 992 | if (ret < 0) { |
950 | mlog_errno(ret); | 993 | mlog_errno(ret); |
@@ -957,7 +1000,7 @@ out_update_size: | |||
957 | mlog_errno(ret); | 1000 | mlog_errno(ret); |
958 | 1001 | ||
959 | out_unlock: | 1002 | out_unlock: |
960 | if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) | 1003 | if (data_locked) |
961 | ocfs2_data_unlock(inode, 1); | 1004 | ocfs2_data_unlock(inode, 1); |
962 | 1005 | ||
963 | out: | 1006 | out: |
@@ -1231,6 +1274,31 @@ static int ocfs2_allocate_unwritten_extents(struct inode *inode, | |||
1231 | { | 1274 | { |
1232 | int ret; | 1275 | int ret; |
1233 | u32 cpos, phys_cpos, clusters, alloc_size; | 1276 | u32 cpos, phys_cpos, clusters, alloc_size; |
1277 | u64 end = start + len; | ||
1278 | struct buffer_head *di_bh = NULL; | ||
1279 | |||
1280 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
1281 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | ||
1282 | OCFS2_I(inode)->ip_blkno, &di_bh, | ||
1283 | OCFS2_BH_CACHED, inode); | ||
1284 | if (ret) { | ||
1285 | mlog_errno(ret); | ||
1286 | goto out; | ||
1287 | } | ||
1288 | |||
1289 | /* | ||
1290 | * Nothing to do if the requested reservation range | ||
1291 | * fits within the inode. | ||
1292 | */ | ||
1293 | if (ocfs2_size_fits_inline_data(di_bh, end)) | ||
1294 | goto out; | ||
1295 | |||
1296 | ret = ocfs2_convert_inline_data_to_extents(inode, di_bh); | ||
1297 | if (ret) { | ||
1298 | mlog_errno(ret); | ||
1299 | goto out; | ||
1300 | } | ||
1301 | } | ||
1234 | 1302 | ||
1235 | /* | 1303 | /* |
1236 | * We consider both start and len to be inclusive. | 1304 | * We consider both start and len to be inclusive. |
@@ -1276,6 +1344,8 @@ next: | |||
1276 | 1344 | ||
1277 | ret = 0; | 1345 | ret = 0; |
1278 | out: | 1346 | out: |
1347 | |||
1348 | brelse(di_bh); | ||
1279 | return ret; | 1349 | return ret; |
1280 | } | 1350 | } |
1281 | 1351 | ||
@@ -1457,6 +1527,14 @@ static int ocfs2_remove_inode_range(struct inode *inode, | |||
1457 | if (byte_len == 0) | 1527 | if (byte_len == 0) |
1458 | return 0; | 1528 | return 0; |
1459 | 1529 | ||
1530 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
1531 | ret = ocfs2_truncate_inline(inode, di_bh, byte_start, | ||
1532 | byte_start + byte_len, 1); | ||
1533 | if (ret) | ||
1534 | mlog_errno(ret); | ||
1535 | return ret; | ||
1536 | } | ||
1537 | |||
1460 | trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start); | 1538 | trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start); |
1461 | trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits; | 1539 | trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits; |
1462 | if (trunc_len >= trunc_start) | 1540 | if (trunc_len >= trunc_start) |
@@ -1759,6 +1837,15 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, | |||
1759 | break; | 1837 | break; |
1760 | 1838 | ||
1761 | /* | 1839 | /* |
1840 | * There's no sane way to do direct writes to an inode | ||
1841 | * with inline data. | ||
1842 | */ | ||
1843 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
1844 | *direct_io = 0; | ||
1845 | break; | ||
1846 | } | ||
1847 | |||
1848 | /* | ||
1762 | * Allowing concurrent direct writes means | 1849 | * Allowing concurrent direct writes means |
1763 | * i_size changes wouldn't be synchronized, so | 1850 | * i_size changes wouldn't be synchronized, so |
1764 | * one node could wind up truncating another | 1851 | * one node could wind up truncating another |