diff options
Diffstat (limited to 'fs/ocfs2/file.c')
-rw-r--r-- | fs/ocfs2/file.c | 236 |
1 files changed, 177 insertions, 59 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index a5fbd9cea968..97e54b9e654b 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -278,10 +278,7 @@ int ocfs2_update_inode_atime(struct inode *inode, | |||
278 | inode->i_atime = CURRENT_TIME; | 278 | inode->i_atime = CURRENT_TIME; |
279 | di->i_atime = cpu_to_le64(inode->i_atime.tv_sec); | 279 | di->i_atime = cpu_to_le64(inode->i_atime.tv_sec); |
280 | di->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); | 280 | di->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); |
281 | 281 | ocfs2_journal_dirty(handle, bh); | |
282 | ret = ocfs2_journal_dirty(handle, bh); | ||
283 | if (ret < 0) | ||
284 | mlog_errno(ret); | ||
285 | 282 | ||
286 | out_commit: | 283 | out_commit: |
287 | ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); | 284 | ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); |
@@ -430,9 +427,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, | |||
430 | di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec); | 427 | di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec); |
431 | di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); | 428 | di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); |
432 | 429 | ||
433 | status = ocfs2_journal_dirty(handle, fe_bh); | 430 | ocfs2_journal_dirty(handle, fe_bh); |
434 | if (status < 0) | ||
435 | mlog_errno(status); | ||
436 | 431 | ||
437 | out_commit: | 432 | out_commit: |
438 | ocfs2_commit_trans(osb, handle); | 433 | ocfs2_commit_trans(osb, handle); |
@@ -449,7 +444,6 @@ static int ocfs2_truncate_file(struct inode *inode, | |||
449 | int status = 0; | 444 | int status = 0; |
450 | struct ocfs2_dinode *fe = NULL; | 445 | struct ocfs2_dinode *fe = NULL; |
451 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 446 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
452 | struct ocfs2_truncate_context *tc = NULL; | ||
453 | 447 | ||
454 | mlog_entry("(inode = %llu, new_i_size = %llu\n", | 448 | mlog_entry("(inode = %llu, new_i_size = %llu\n", |
455 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | 449 | (unsigned long long)OCFS2_I(inode)->ip_blkno, |
@@ -488,6 +482,9 @@ static int ocfs2_truncate_file(struct inode *inode, | |||
488 | 482 | ||
489 | down_write(&OCFS2_I(inode)->ip_alloc_sem); | 483 | down_write(&OCFS2_I(inode)->ip_alloc_sem); |
490 | 484 | ||
485 | ocfs2_resv_discard(&osb->osb_la_resmap, | ||
486 | &OCFS2_I(inode)->ip_la_data_resv); | ||
487 | |||
491 | /* | 488 | /* |
492 | * The inode lock forced other nodes to sync and drop their | 489 | * The inode lock forced other nodes to sync and drop their |
493 | * pages, which (correctly) happens even if we have a truncate | 490 | * pages, which (correctly) happens even if we have a truncate |
@@ -517,13 +514,7 @@ static int ocfs2_truncate_file(struct inode *inode, | |||
517 | goto bail_unlock_sem; | 514 | goto bail_unlock_sem; |
518 | } | 515 | } |
519 | 516 | ||
520 | status = ocfs2_prepare_truncate(osb, inode, di_bh, &tc); | 517 | status = ocfs2_commit_truncate(osb, inode, di_bh); |
521 | if (status < 0) { | ||
522 | mlog_errno(status); | ||
523 | goto bail_unlock_sem; | ||
524 | } | ||
525 | |||
526 | status = ocfs2_commit_truncate(osb, inode, di_bh, tc); | ||
527 | if (status < 0) { | 518 | if (status < 0) { |
528 | mlog_errno(status); | 519 | mlog_errno(status); |
529 | goto bail_unlock_sem; | 520 | goto bail_unlock_sem; |
@@ -666,11 +657,7 @@ restarted_transaction: | |||
666 | goto leave; | 657 | goto leave; |
667 | } | 658 | } |
668 | 659 | ||
669 | status = ocfs2_journal_dirty(handle, bh); | 660 | ocfs2_journal_dirty(handle, bh); |
670 | if (status < 0) { | ||
671 | mlog_errno(status); | ||
672 | goto leave; | ||
673 | } | ||
674 | 661 | ||
675 | spin_lock(&OCFS2_I(inode)->ip_lock); | 662 | spin_lock(&OCFS2_I(inode)->ip_lock); |
676 | clusters_to_add -= (OCFS2_I(inode)->ip_clusters - prev_clusters); | 663 | clusters_to_add -= (OCFS2_I(inode)->ip_clusters - prev_clusters); |
@@ -946,9 +933,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
946 | struct ocfs2_super *osb = OCFS2_SB(sb); | 933 | struct ocfs2_super *osb = OCFS2_SB(sb); |
947 | struct buffer_head *bh = NULL; | 934 | struct buffer_head *bh = NULL; |
948 | handle_t *handle = NULL; | 935 | handle_t *handle = NULL; |
949 | int qtype; | ||
950 | struct dquot *transfer_from[MAXQUOTAS] = { }; | ||
951 | struct dquot *transfer_to[MAXQUOTAS] = { }; | 936 | struct dquot *transfer_to[MAXQUOTAS] = { }; |
937 | int qtype; | ||
952 | 938 | ||
953 | mlog_entry("(0x%p, '%.*s')\n", dentry, | 939 | mlog_entry("(0x%p, '%.*s')\n", dentry, |
954 | dentry->d_name.len, dentry->d_name.name); | 940 | dentry->d_name.len, dentry->d_name.name); |
@@ -979,10 +965,10 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
979 | if (status) | 965 | if (status) |
980 | return status; | 966 | return status; |
981 | 967 | ||
968 | if (is_quota_modification(inode, attr)) | ||
969 | dquot_initialize(inode); | ||
982 | size_change = S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE; | 970 | size_change = S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE; |
983 | if (size_change) { | 971 | if (size_change) { |
984 | dquot_initialize(inode); | ||
985 | |||
986 | status = ocfs2_rw_lock(inode, 1); | 972 | status = ocfs2_rw_lock(inode, 1); |
987 | if (status < 0) { | 973 | if (status < 0) { |
988 | mlog_errno(status); | 974 | mlog_errno(status); |
@@ -1032,9 +1018,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
1032 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { | 1018 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { |
1033 | transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid, | 1019 | transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid, |
1034 | USRQUOTA); | 1020 | USRQUOTA); |
1035 | transfer_from[USRQUOTA] = dqget(sb, inode->i_uid, | 1021 | if (!transfer_to[USRQUOTA]) { |
1036 | USRQUOTA); | ||
1037 | if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) { | ||
1038 | status = -ESRCH; | 1022 | status = -ESRCH; |
1039 | goto bail_unlock; | 1023 | goto bail_unlock; |
1040 | } | 1024 | } |
@@ -1044,9 +1028,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
1044 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { | 1028 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { |
1045 | transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid, | 1029 | transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid, |
1046 | GRPQUOTA); | 1030 | GRPQUOTA); |
1047 | transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid, | 1031 | if (!transfer_to[GRPQUOTA]) { |
1048 | GRPQUOTA); | ||
1049 | if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) { | ||
1050 | status = -ESRCH; | 1032 | status = -ESRCH; |
1051 | goto bail_unlock; | 1033 | goto bail_unlock; |
1052 | } | 1034 | } |
@@ -1058,7 +1040,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
1058 | mlog_errno(status); | 1040 | mlog_errno(status); |
1059 | goto bail_unlock; | 1041 | goto bail_unlock; |
1060 | } | 1042 | } |
1061 | status = dquot_transfer(inode, attr); | 1043 | status = __dquot_transfer(inode, transfer_to); |
1062 | if (status < 0) | 1044 | if (status < 0) |
1063 | goto bail_commit; | 1045 | goto bail_commit; |
1064 | } else { | 1046 | } else { |
@@ -1098,10 +1080,8 @@ bail: | |||
1098 | brelse(bh); | 1080 | brelse(bh); |
1099 | 1081 | ||
1100 | /* Release quota pointers in case we acquired them */ | 1082 | /* Release quota pointers in case we acquired them */ |
1101 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) { | 1083 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) |
1102 | dqput(transfer_to[qtype]); | 1084 | dqput(transfer_to[qtype]); |
1103 | dqput(transfer_from[qtype]); | ||
1104 | } | ||
1105 | 1085 | ||
1106 | if (!status && attr->ia_valid & ATTR_MODE) { | 1086 | if (!status && attr->ia_valid & ATTR_MODE) { |
1107 | status = ocfs2_acl_chmod(inode); | 1087 | status = ocfs2_acl_chmod(inode); |
@@ -1195,9 +1175,7 @@ static int __ocfs2_write_remove_suid(struct inode *inode, | |||
1195 | di = (struct ocfs2_dinode *) bh->b_data; | 1175 | di = (struct ocfs2_dinode *) bh->b_data; |
1196 | di->i_mode = cpu_to_le16(inode->i_mode); | 1176 | di->i_mode = cpu_to_le16(inode->i_mode); |
1197 | 1177 | ||
1198 | ret = ocfs2_journal_dirty(handle, bh); | 1178 | ocfs2_journal_dirty(handle, bh); |
1199 | if (ret < 0) | ||
1200 | mlog_errno(ret); | ||
1201 | 1179 | ||
1202 | out_trans: | 1180 | out_trans: |
1203 | ocfs2_commit_trans(osb, handle); | 1181 | ocfs2_commit_trans(osb, handle); |
@@ -1434,16 +1412,90 @@ out: | |||
1434 | return ret; | 1412 | return ret; |
1435 | } | 1413 | } |
1436 | 1414 | ||
1415 | static int ocfs2_find_rec(struct ocfs2_extent_list *el, u32 pos) | ||
1416 | { | ||
1417 | int i; | ||
1418 | struct ocfs2_extent_rec *rec = NULL; | ||
1419 | |||
1420 | for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) { | ||
1421 | |||
1422 | rec = &el->l_recs[i]; | ||
1423 | |||
1424 | if (le32_to_cpu(rec->e_cpos) < pos) | ||
1425 | break; | ||
1426 | } | ||
1427 | |||
1428 | return i; | ||
1429 | } | ||
1430 | |||
1431 | /* | ||
1432 | * Helper to calculate the punching pos and length in one run, we handle the | ||
1433 | * following three cases in order: | ||
1434 | * | ||
1435 | * - remove the entire record | ||
1436 | * - remove a partial record | ||
1437 | * - no record needs to be removed (hole-punching completed) | ||
1438 | */ | ||
1439 | static void ocfs2_calc_trunc_pos(struct inode *inode, | ||
1440 | struct ocfs2_extent_list *el, | ||
1441 | struct ocfs2_extent_rec *rec, | ||
1442 | u32 trunc_start, u32 *trunc_cpos, | ||
1443 | u32 *trunc_len, u32 *trunc_end, | ||
1444 | u64 *blkno, int *done) | ||
1445 | { | ||
1446 | int ret = 0; | ||
1447 | u32 coff, range; | ||
1448 | |||
1449 | range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec); | ||
1450 | |||
1451 | if (le32_to_cpu(rec->e_cpos) >= trunc_start) { | ||
1452 | *trunc_cpos = le32_to_cpu(rec->e_cpos); | ||
1453 | /* | ||
1454 | * Skip holes if any. | ||
1455 | */ | ||
1456 | if (range < *trunc_end) | ||
1457 | *trunc_end = range; | ||
1458 | *trunc_len = *trunc_end - le32_to_cpu(rec->e_cpos); | ||
1459 | *blkno = le64_to_cpu(rec->e_blkno); | ||
1460 | *trunc_end = le32_to_cpu(rec->e_cpos); | ||
1461 | } else if (range > trunc_start) { | ||
1462 | *trunc_cpos = trunc_start; | ||
1463 | *trunc_len = *trunc_end - trunc_start; | ||
1464 | coff = trunc_start - le32_to_cpu(rec->e_cpos); | ||
1465 | *blkno = le64_to_cpu(rec->e_blkno) + | ||
1466 | ocfs2_clusters_to_blocks(inode->i_sb, coff); | ||
1467 | *trunc_end = trunc_start; | ||
1468 | } else { | ||
1469 | /* | ||
1470 | * It may have two following possibilities: | ||
1471 | * | ||
1472 | * - last record has been removed | ||
1473 | * - trunc_start was within a hole | ||
1474 | * | ||
1475 | * both two cases mean the completion of hole punching. | ||
1476 | */ | ||
1477 | ret = 1; | ||
1478 | } | ||
1479 | |||
1480 | *done = ret; | ||
1481 | } | ||
1482 | |||
1437 | static int ocfs2_remove_inode_range(struct inode *inode, | 1483 | static int ocfs2_remove_inode_range(struct inode *inode, |
1438 | struct buffer_head *di_bh, u64 byte_start, | 1484 | struct buffer_head *di_bh, u64 byte_start, |
1439 | u64 byte_len) | 1485 | u64 byte_len) |
1440 | { | 1486 | { |
1441 | int ret = 0; | 1487 | int ret = 0, flags = 0, done = 0, i; |
1442 | u32 trunc_start, trunc_len, cpos, phys_cpos, alloc_size; | 1488 | u32 trunc_start, trunc_len, trunc_end, trunc_cpos, phys_cpos; |
1489 | u32 cluster_in_el; | ||
1443 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 1490 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
1444 | struct ocfs2_cached_dealloc_ctxt dealloc; | 1491 | struct ocfs2_cached_dealloc_ctxt dealloc; |
1445 | struct address_space *mapping = inode->i_mapping; | 1492 | struct address_space *mapping = inode->i_mapping; |
1446 | struct ocfs2_extent_tree et; | 1493 | struct ocfs2_extent_tree et; |
1494 | struct ocfs2_path *path = NULL; | ||
1495 | struct ocfs2_extent_list *el = NULL; | ||
1496 | struct ocfs2_extent_rec *rec = NULL; | ||
1497 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | ||
1498 | u64 blkno, refcount_loc = le64_to_cpu(di->i_refcount_loc); | ||
1447 | 1499 | ||
1448 | ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh); | 1500 | ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh); |
1449 | ocfs2_init_dealloc_ctxt(&dealloc); | 1501 | ocfs2_init_dealloc_ctxt(&dealloc); |
@@ -1469,17 +1521,35 @@ static int ocfs2_remove_inode_range(struct inode *inode, | |||
1469 | goto out; | 1521 | goto out; |
1470 | } | 1522 | } |
1471 | 1523 | ||
1524 | /* | ||
1525 | * For reflinks, we may need to CoW 2 clusters which might be | ||
1526 | * partially zero'd later, if hole's start and end offset were | ||
1527 | * within one cluster(means is not exactly aligned to clustersize). | ||
1528 | */ | ||
1529 | |||
1530 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) { | ||
1531 | |||
1532 | ret = ocfs2_cow_file_pos(inode, di_bh, byte_start); | ||
1533 | if (ret) { | ||
1534 | mlog_errno(ret); | ||
1535 | goto out; | ||
1536 | } | ||
1537 | |||
1538 | ret = ocfs2_cow_file_pos(inode, di_bh, byte_start + byte_len); | ||
1539 | if (ret) { | ||
1540 | mlog_errno(ret); | ||
1541 | goto out; | ||
1542 | } | ||
1543 | } | ||
1544 | |||
1472 | trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start); | 1545 | trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start); |
1473 | trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits; | 1546 | trunc_end = (byte_start + byte_len) >> osb->s_clustersize_bits; |
1474 | if (trunc_len >= trunc_start) | 1547 | cluster_in_el = trunc_end; |
1475 | trunc_len -= trunc_start; | ||
1476 | else | ||
1477 | trunc_len = 0; | ||
1478 | 1548 | ||
1479 | mlog(0, "Inode: %llu, start: %llu, len: %llu, cstart: %u, clen: %u\n", | 1549 | mlog(0, "Inode: %llu, start: %llu, len: %llu, cstart: %u, cend: %u\n", |
1480 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | 1550 | (unsigned long long)OCFS2_I(inode)->ip_blkno, |
1481 | (unsigned long long)byte_start, | 1551 | (unsigned long long)byte_start, |
1482 | (unsigned long long)byte_len, trunc_start, trunc_len); | 1552 | (unsigned long long)byte_len, trunc_start, trunc_end); |
1483 | 1553 | ||
1484 | ret = ocfs2_zero_partial_clusters(inode, byte_start, byte_len); | 1554 | ret = ocfs2_zero_partial_clusters(inode, byte_start, byte_len); |
1485 | if (ret) { | 1555 | if (ret) { |
@@ -1487,31 +1557,79 @@ static int ocfs2_remove_inode_range(struct inode *inode, | |||
1487 | goto out; | 1557 | goto out; |
1488 | } | 1558 | } |
1489 | 1559 | ||
1490 | cpos = trunc_start; | 1560 | path = ocfs2_new_path_from_et(&et); |
1491 | while (trunc_len) { | 1561 | if (!path) { |
1492 | ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, | 1562 | ret = -ENOMEM; |
1493 | &alloc_size, NULL); | 1563 | mlog_errno(ret); |
1564 | goto out; | ||
1565 | } | ||
1566 | |||
1567 | while (trunc_end > trunc_start) { | ||
1568 | |||
1569 | ret = ocfs2_find_path(INODE_CACHE(inode), path, | ||
1570 | cluster_in_el); | ||
1494 | if (ret) { | 1571 | if (ret) { |
1495 | mlog_errno(ret); | 1572 | mlog_errno(ret); |
1496 | goto out; | 1573 | goto out; |
1497 | } | 1574 | } |
1498 | 1575 | ||
1499 | if (alloc_size > trunc_len) | 1576 | el = path_leaf_el(path); |
1500 | alloc_size = trunc_len; | 1577 | |
1578 | i = ocfs2_find_rec(el, trunc_end); | ||
1579 | /* | ||
1580 | * Need to go to previous extent block. | ||
1581 | */ | ||
1582 | if (i < 0) { | ||
1583 | if (path->p_tree_depth == 0) | ||
1584 | break; | ||
1501 | 1585 | ||
1502 | /* Only do work for non-holes */ | 1586 | ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, |
1503 | if (phys_cpos != 0) { | 1587 | path, |
1504 | ret = ocfs2_remove_btree_range(inode, &et, cpos, | 1588 | &cluster_in_el); |
1505 | phys_cpos, alloc_size, | ||
1506 | &dealloc); | ||
1507 | if (ret) { | 1589 | if (ret) { |
1508 | mlog_errno(ret); | 1590 | mlog_errno(ret); |
1509 | goto out; | 1591 | goto out; |
1510 | } | 1592 | } |
1593 | |||
1594 | /* | ||
1595 | * We've reached the leftmost extent block, | ||
1596 | * it's safe to leave. | ||
1597 | */ | ||
1598 | if (cluster_in_el == 0) | ||
1599 | break; | ||
1600 | |||
1601 | /* | ||
1602 | * The 'pos' searched for previous extent block is | ||
1603 | * always one cluster less than actual trunc_end. | ||
1604 | */ | ||
1605 | trunc_end = cluster_in_el + 1; | ||
1606 | |||
1607 | ocfs2_reinit_path(path, 1); | ||
1608 | |||
1609 | continue; | ||
1610 | |||
1611 | } else | ||
1612 | rec = &el->l_recs[i]; | ||
1613 | |||
1614 | ocfs2_calc_trunc_pos(inode, el, rec, trunc_start, &trunc_cpos, | ||
1615 | &trunc_len, &trunc_end, &blkno, &done); | ||
1616 | if (done) | ||
1617 | break; | ||
1618 | |||
1619 | flags = rec->e_flags; | ||
1620 | phys_cpos = ocfs2_blocks_to_clusters(inode->i_sb, blkno); | ||
1621 | |||
1622 | ret = ocfs2_remove_btree_range(inode, &et, trunc_cpos, | ||
1623 | phys_cpos, trunc_len, flags, | ||
1624 | &dealloc, refcount_loc); | ||
1625 | if (ret < 0) { | ||
1626 | mlog_errno(ret); | ||
1627 | goto out; | ||
1511 | } | 1628 | } |
1512 | 1629 | ||
1513 | cpos += alloc_size; | 1630 | cluster_in_el = trunc_end; |
1514 | trunc_len -= alloc_size; | 1631 | |
1632 | ocfs2_reinit_path(path, 1); | ||
1515 | } | 1633 | } |
1516 | 1634 | ||
1517 | ocfs2_truncate_cluster_pages(inode, byte_start, byte_len); | 1635 | ocfs2_truncate_cluster_pages(inode, byte_start, byte_len); |