diff options
author | Joel Becker <joel.becker@oracle.com> | 2009-08-18 23:26:41 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2010-02-26 18:41:11 -0500 |
commit | 73857ee0b548017f9632a0d0e6fe2dabbdc11d31 (patch) | |
tree | f073a4e84c3df446f6ed2dd5c58ff27708b51dd0 /fs/ocfs2/xattr.c | |
parent | cf2bc809403ae48a4a2bb5cc551d2ec35f2e4a47 (diff) |
ocfs2: Allocation in ocfs2_xa_prepare_entry(), values in ocfs2_xa_store_value()
ocfs2_xa_prepare_entry() gets all the logic to add, remove, or modify
external value trees. Now, when it exits, the entry is ready to receive
a value of any size.
ocfs2_xa_remove() is added to handle the complete removal of an entry.
It truncates the external value tree before calling
ocfs2_xa_remove_entry().
ocfs2_xa_store_inline_value() becomes ocfs2_xa_store_value(). It can
store any value.
ocfs2_xattr_set_entry() loses all the allocation logic and just uses
these functions. ocfs2_xattr_set_value_outside() disappears.
ocfs2_xattr_set_in_bucket() uses these functions and makes
ocfs2_xattr_set_entry_in_bucket() obsolete. That goes away, as does
ocfs2_xattr_bucket_set_value_outside() and
ocfs2_xattr_bucket_value_truncate().
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2/xattr.c')
-rw-r--r-- | fs/ocfs2/xattr.c | 661 |
1 files changed, 186 insertions, 475 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index fbec11610223..550a3e86c971 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -573,24 +573,6 @@ static u32 ocfs2_xattr_name_hash(struct inode *inode, | |||
573 | return hash; | 573 | return hash; |
574 | } | 574 | } |
575 | 575 | ||
576 | /* | ||
577 | * ocfs2_xattr_hash_entry() | ||
578 | * | ||
579 | * Compute the hash of an extended attribute. | ||
580 | */ | ||
581 | static void ocfs2_xattr_hash_entry(struct inode *inode, | ||
582 | struct ocfs2_xattr_header *header, | ||
583 | struct ocfs2_xattr_entry *entry) | ||
584 | { | ||
585 | u32 hash = 0; | ||
586 | char *name = (char *)header + le16_to_cpu(entry->xe_name_offset); | ||
587 | |||
588 | hash = ocfs2_xattr_name_hash(inode, name, entry->xe_name_len); | ||
589 | entry->xe_name_hash = cpu_to_le32(hash); | ||
590 | |||
591 | return; | ||
592 | } | ||
593 | |||
594 | static int ocfs2_xattr_entry_real_size(int name_len, size_t value_len) | 576 | static int ocfs2_xattr_entry_real_size(int name_len, size_t value_len) |
595 | { | 577 | { |
596 | return namevalue_size(name_len, value_len) + | 578 | return namevalue_size(name_len, value_len) + |
@@ -1423,113 +1405,6 @@ out: | |||
1423 | return ret; | 1405 | return ret; |
1424 | } | 1406 | } |
1425 | 1407 | ||
1426 | static int ocfs2_xattr_cleanup(struct inode *inode, | ||
1427 | handle_t *handle, | ||
1428 | struct ocfs2_xattr_info *xi, | ||
1429 | struct ocfs2_xattr_search *xs, | ||
1430 | struct ocfs2_xattr_value_buf *vb, | ||
1431 | size_t offs) | ||
1432 | { | ||
1433 | int ret = 0; | ||
1434 | void *val = xs->base + offs; | ||
1435 | size_t size = namevalue_size_xi(xi); | ||
1436 | |||
1437 | ret = vb->vb_access(handle, INODE_CACHE(inode), vb->vb_bh, | ||
1438 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
1439 | if (ret) { | ||
1440 | mlog_errno(ret); | ||
1441 | goto out; | ||
1442 | } | ||
1443 | /* Decrease xattr count */ | ||
1444 | le16_add_cpu(&xs->header->xh_count, -1); | ||
1445 | /* Remove the xattr entry and tree root which has already be set*/ | ||
1446 | memset((void *)xs->here, 0, sizeof(struct ocfs2_xattr_entry)); | ||
1447 | memset(val, 0, size); | ||
1448 | |||
1449 | ret = ocfs2_journal_dirty(handle, vb->vb_bh); | ||
1450 | if (ret < 0) | ||
1451 | mlog_errno(ret); | ||
1452 | out: | ||
1453 | return ret; | ||
1454 | } | ||
1455 | |||
1456 | static int ocfs2_xattr_update_entry(struct inode *inode, | ||
1457 | handle_t *handle, | ||
1458 | struct ocfs2_xattr_info *xi, | ||
1459 | struct ocfs2_xattr_search *xs, | ||
1460 | struct ocfs2_xattr_value_buf *vb, | ||
1461 | size_t offs) | ||
1462 | { | ||
1463 | int ret; | ||
1464 | |||
1465 | ret = vb->vb_access(handle, INODE_CACHE(inode), vb->vb_bh, | ||
1466 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
1467 | if (ret) { | ||
1468 | mlog_errno(ret); | ||
1469 | goto out; | ||
1470 | } | ||
1471 | |||
1472 | xs->here->xe_name_offset = cpu_to_le16(offs); | ||
1473 | xs->here->xe_value_size = cpu_to_le64(xi->xi_value_len); | ||
1474 | if (xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE) | ||
1475 | ocfs2_xattr_set_local(xs->here, 1); | ||
1476 | else | ||
1477 | ocfs2_xattr_set_local(xs->here, 0); | ||
1478 | ocfs2_xattr_hash_entry(inode, xs->header, xs->here); | ||
1479 | |||
1480 | ret = ocfs2_journal_dirty(handle, vb->vb_bh); | ||
1481 | if (ret < 0) | ||
1482 | mlog_errno(ret); | ||
1483 | out: | ||
1484 | return ret; | ||
1485 | } | ||
1486 | |||
1487 | /* | ||
1488 | * ocfs2_xattr_set_value_outside() | ||
1489 | * | ||
1490 | * Set large size value in B tree. | ||
1491 | */ | ||
1492 | static int ocfs2_xattr_set_value_outside(struct inode *inode, | ||
1493 | struct ocfs2_xattr_info *xi, | ||
1494 | struct ocfs2_xattr_search *xs, | ||
1495 | struct ocfs2_xattr_set_ctxt *ctxt, | ||
1496 | struct ocfs2_xattr_value_buf *vb, | ||
1497 | size_t offs) | ||
1498 | { | ||
1499 | void *val = xs->base + offs; | ||
1500 | struct ocfs2_xattr_value_root *xv = NULL; | ||
1501 | size_t size = namevalue_size_xi(xi); | ||
1502 | int ret = 0; | ||
1503 | |||
1504 | memset(val, 0, size); | ||
1505 | memcpy(val, xi->xi_name, xi->xi_name_len); | ||
1506 | xv = (struct ocfs2_xattr_value_root *) | ||
1507 | (val + OCFS2_XATTR_SIZE(xi->xi_name_len)); | ||
1508 | xv->xr_clusters = 0; | ||
1509 | xv->xr_last_eb_blk = 0; | ||
1510 | xv->xr_list.l_tree_depth = 0; | ||
1511 | xv->xr_list.l_count = cpu_to_le16(1); | ||
1512 | xv->xr_list.l_next_free_rec = 0; | ||
1513 | vb->vb_xv = xv; | ||
1514 | |||
1515 | ret = ocfs2_xattr_value_truncate(inode, vb, xi->xi_value_len, ctxt); | ||
1516 | if (ret < 0) { | ||
1517 | mlog_errno(ret); | ||
1518 | return ret; | ||
1519 | } | ||
1520 | ret = ocfs2_xattr_update_entry(inode, ctxt->handle, xi, xs, vb, offs); | ||
1521 | if (ret < 0) { | ||
1522 | mlog_errno(ret); | ||
1523 | return ret; | ||
1524 | } | ||
1525 | ret = __ocfs2_xattr_set_value_outside(inode, ctxt->handle, vb, | ||
1526 | xi->xi_value, xi->xi_value_len); | ||
1527 | if (ret < 0) | ||
1528 | mlog_errno(ret); | ||
1529 | |||
1530 | return ret; | ||
1531 | } | ||
1532 | |||
1533 | static int ocfs2_xa_check_space_helper(int needed_space, int free_start, | 1408 | static int ocfs2_xa_check_space_helper(int needed_space, int free_start, |
1534 | int num_entries) | 1409 | int num_entries) |
1535 | { | 1410 | { |
@@ -1640,6 +1515,7 @@ static void ocfs2_xa_fill_value_buf(struct ocfs2_xa_loc *loc, | |||
1640 | int name_size = OCFS2_XATTR_SIZE(loc->xl_entry->xe_name_len); | 1515 | int name_size = OCFS2_XATTR_SIZE(loc->xl_entry->xe_name_len); |
1641 | 1516 | ||
1642 | /* Value bufs are for value trees */ | 1517 | /* Value bufs are for value trees */ |
1518 | BUG_ON(ocfs2_xattr_is_local(loc->xl_entry)); | ||
1643 | BUG_ON(namevalue_size_xe(loc->xl_entry) != | 1519 | BUG_ON(namevalue_size_xe(loc->xl_entry) != |
1644 | (name_size + OCFS2_XATTR_ROOT_SIZE)); | 1520 | (name_size + OCFS2_XATTR_ROOT_SIZE)); |
1645 | 1521 | ||
@@ -2001,6 +1877,33 @@ static const struct ocfs2_xa_loc_operations ocfs2_xa_bucket_loc_ops = { | |||
2001 | .xlo_fill_value_buf = ocfs2_xa_bucket_fill_value_buf, | 1877 | .xlo_fill_value_buf = ocfs2_xa_bucket_fill_value_buf, |
2002 | }; | 1878 | }; |
2003 | 1879 | ||
1880 | static int ocfs2_xa_value_truncate(struct ocfs2_xa_loc *loc, u64 bytes, | ||
1881 | struct ocfs2_xattr_set_ctxt *ctxt) | ||
1882 | { | ||
1883 | int trunc_rc, access_rc; | ||
1884 | struct ocfs2_xattr_value_buf vb; | ||
1885 | |||
1886 | ocfs2_xa_fill_value_buf(loc, &vb); | ||
1887 | trunc_rc = ocfs2_xattr_value_truncate(loc->xl_inode, &vb, bytes, | ||
1888 | ctxt); | ||
1889 | |||
1890 | /* | ||
1891 | * The caller of ocfs2_xa_value_truncate() has already called | ||
1892 | * ocfs2_xa_journal_access on the loc. However, The truncate code | ||
1893 | * calls ocfs2_extend_trans(). This may commit the previous | ||
1894 | * transaction and open a new one. If this is a bucket, truncate | ||
1895 | * could leave only vb->vb_bh set up for journaling. Meanwhile, | ||
1896 | * the caller is expecting to dirty the entire bucket. So we must | ||
1897 | * reset the journal work. We do this even if truncate has failed, | ||
1898 | * as it could have failed after committing the extend. | ||
1899 | */ | ||
1900 | access_rc = ocfs2_xa_journal_access(ctxt->handle, loc, | ||
1901 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
1902 | |||
1903 | /* Errors in truncate take precedence */ | ||
1904 | return trunc_rc ? trunc_rc : access_rc; | ||
1905 | } | ||
1906 | |||
2004 | static void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc) | 1907 | static void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc) |
2005 | { | 1908 | { |
2006 | int index, count; | 1909 | int index, count; |
@@ -2028,6 +1931,88 @@ static void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc) | |||
2028 | } | 1931 | } |
2029 | } | 1932 | } |
2030 | 1933 | ||
1934 | static int ocfs2_xa_remove(struct ocfs2_xa_loc *loc, | ||
1935 | struct ocfs2_xattr_set_ctxt *ctxt) | ||
1936 | { | ||
1937 | int rc = 0; | ||
1938 | |||
1939 | if (!ocfs2_xattr_is_local(loc->xl_entry)) { | ||
1940 | rc = ocfs2_xa_value_truncate(loc, 0, ctxt); | ||
1941 | if (rc) { | ||
1942 | mlog_errno(rc); | ||
1943 | goto out; | ||
1944 | } | ||
1945 | } | ||
1946 | |||
1947 | ocfs2_xa_remove_entry(loc); | ||
1948 | |||
1949 | out: | ||
1950 | return rc; | ||
1951 | } | ||
1952 | |||
1953 | static void ocfs2_xa_install_value_root(struct ocfs2_xa_loc *loc) | ||
1954 | { | ||
1955 | int name_size = OCFS2_XATTR_SIZE(loc->xl_entry->xe_name_len); | ||
1956 | char *nameval_buf; | ||
1957 | |||
1958 | nameval_buf = ocfs2_xa_offset_pointer(loc, | ||
1959 | le16_to_cpu(loc->xl_entry->xe_name_offset)); | ||
1960 | memcpy(nameval_buf + name_size, &def_xv, OCFS2_XATTR_ROOT_SIZE); | ||
1961 | } | ||
1962 | |||
1963 | /* | ||
1964 | * Take an existing entry and make it ready for the new value. This | ||
1965 | * won't allocate space, but it may free space. It should be ready for | ||
1966 | * ocfs2_xa_prepare_entry() to finish the work. | ||
1967 | */ | ||
1968 | static int ocfs2_xa_reuse_entry(struct ocfs2_xa_loc *loc, | ||
1969 | struct ocfs2_xattr_info *xi, | ||
1970 | struct ocfs2_xattr_set_ctxt *ctxt) | ||
1971 | { | ||
1972 | int rc = 0; | ||
1973 | int name_size = OCFS2_XATTR_SIZE(xi->xi_name_len); | ||
1974 | char *nameval_buf; | ||
1975 | int xe_local = ocfs2_xattr_is_local(loc->xl_entry); | ||
1976 | int xi_local = xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE; | ||
1977 | |||
1978 | BUG_ON(OCFS2_XATTR_SIZE(loc->xl_entry->xe_name_len) != | ||
1979 | name_size); | ||
1980 | |||
1981 | nameval_buf = ocfs2_xa_offset_pointer(loc, | ||
1982 | le16_to_cpu(loc->xl_entry->xe_name_offset)); | ||
1983 | if (xe_local) { | ||
1984 | memset(nameval_buf + name_size, 0, | ||
1985 | namevalue_size_xe(loc->xl_entry) - name_size); | ||
1986 | if (!xi_local) | ||
1987 | ocfs2_xa_install_value_root(loc); | ||
1988 | } else { | ||
1989 | if (xi_local) { | ||
1990 | rc = ocfs2_xa_value_truncate(loc, 0, ctxt); | ||
1991 | if (rc < 0) { | ||
1992 | mlog_errno(rc); | ||
1993 | goto out; | ||
1994 | } | ||
1995 | memset(nameval_buf + name_size, 0, | ||
1996 | namevalue_size_xe(loc->xl_entry) - | ||
1997 | name_size); | ||
1998 | } else if (le64_to_cpu(loc->xl_entry->xe_value_size) > | ||
1999 | xi->xi_value_len) { | ||
2000 | rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len, | ||
2001 | ctxt); | ||
2002 | if (rc < 0) { | ||
2003 | mlog_errno(rc); | ||
2004 | goto out; | ||
2005 | } | ||
2006 | } | ||
2007 | } | ||
2008 | |||
2009 | loc->xl_entry->xe_value_size = cpu_to_le64(xi->xi_value_len); | ||
2010 | ocfs2_xattr_set_local(loc->xl_entry, xi_local); | ||
2011 | |||
2012 | out: | ||
2013 | return rc; | ||
2014 | } | ||
2015 | |||
2031 | /* | 2016 | /* |
2032 | * Prepares loc->xl_entry to receive the new xattr. This includes | 2017 | * Prepares loc->xl_entry to receive the new xattr. This includes |
2033 | * properly setting up the name+value pair region. If loc->xl_entry | 2018 | * properly setting up the name+value pair region. If loc->xl_entry |
@@ -2040,14 +2025,13 @@ static void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc) | |||
2040 | */ | 2025 | */ |
2041 | static int ocfs2_xa_prepare_entry(struct ocfs2_xa_loc *loc, | 2026 | static int ocfs2_xa_prepare_entry(struct ocfs2_xa_loc *loc, |
2042 | struct ocfs2_xattr_info *xi, | 2027 | struct ocfs2_xattr_info *xi, |
2043 | u32 name_hash) | 2028 | u32 name_hash, |
2029 | struct ocfs2_xattr_set_ctxt *ctxt) | ||
2044 | { | 2030 | { |
2045 | int rc = 0; | 2031 | int rc = 0; |
2046 | int name_size = OCFS2_XATTR_SIZE(xi->xi_name_len); | ||
2047 | char *nameval_buf; | ||
2048 | 2032 | ||
2049 | if (!xi->xi_value) { | 2033 | if (!xi->xi_value) { |
2050 | ocfs2_xa_remove_entry(loc); | 2034 | rc = ocfs2_xa_remove(loc, ctxt); |
2051 | goto out; | 2035 | goto out; |
2052 | } | 2036 | } |
2053 | 2037 | ||
@@ -2057,15 +2041,19 @@ static int ocfs2_xa_prepare_entry(struct ocfs2_xa_loc *loc, | |||
2057 | 2041 | ||
2058 | if (loc->xl_entry) { | 2042 | if (loc->xl_entry) { |
2059 | if (ocfs2_xa_can_reuse_entry(loc, xi)) { | 2043 | if (ocfs2_xa_can_reuse_entry(loc, xi)) { |
2060 | nameval_buf = ocfs2_xa_offset_pointer(loc, | 2044 | rc = ocfs2_xa_reuse_entry(loc, xi, ctxt); |
2061 | le16_to_cpu(loc->xl_entry->xe_name_offset)); | 2045 | if (rc) |
2062 | memset(nameval_buf + name_size, 0, | 2046 | goto out; |
2063 | namevalue_size_xe(loc->xl_entry) - name_size); | 2047 | goto alloc_value; |
2064 | loc->xl_entry->xe_value_size = | ||
2065 | cpu_to_le64(xi->xi_value_len); | ||
2066 | goto out; | ||
2067 | } | 2048 | } |
2068 | 2049 | ||
2050 | if (!ocfs2_xattr_is_local(loc->xl_entry)) { | ||
2051 | rc = ocfs2_xa_value_truncate(loc, 0, ctxt); | ||
2052 | if (rc) { | ||
2053 | mlog_errno(rc); | ||
2054 | goto out; | ||
2055 | } | ||
2056 | } | ||
2069 | ocfs2_xa_wipe_namevalue(loc); | 2057 | ocfs2_xa_wipe_namevalue(loc); |
2070 | } else | 2058 | } else |
2071 | ocfs2_xa_add_entry(loc, name_hash); | 2059 | ocfs2_xa_add_entry(loc, name_hash); |
@@ -2075,33 +2063,50 @@ static int ocfs2_xa_prepare_entry(struct ocfs2_xa_loc *loc, | |||
2075 | * name+value pair back from the end. | 2063 | * name+value pair back from the end. |
2076 | */ | 2064 | */ |
2077 | ocfs2_xa_add_namevalue(loc, xi); | 2065 | ocfs2_xa_add_namevalue(loc, xi); |
2066 | if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) | ||
2067 | ocfs2_xa_install_value_root(loc); | ||
2068 | |||
2069 | alloc_value: | ||
2070 | if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) { | ||
2071 | rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len, ctxt); | ||
2072 | if (rc < 0) | ||
2073 | mlog_errno(rc); | ||
2074 | } | ||
2078 | 2075 | ||
2079 | out: | 2076 | out: |
2080 | return rc; | 2077 | return rc; |
2081 | } | 2078 | } |
2082 | 2079 | ||
2083 | /* | 2080 | /* |
2084 | * Store the value portion of the name+value pair. This is either an | 2081 | * Store the value portion of the name+value pair. This will skip |
2085 | * inline value or the tree root of an external value. | 2082 | * values that are stored externally. Their tree roots were set up |
2083 | * by ocfs2_xa_prepare_entry(). | ||
2086 | */ | 2084 | */ |
2087 | static void ocfs2_xa_store_inline_value(struct ocfs2_xa_loc *loc, | 2085 | static int ocfs2_xa_store_value(struct ocfs2_xa_loc *loc, |
2088 | struct ocfs2_xattr_info *xi) | 2086 | struct ocfs2_xattr_info *xi, |
2087 | struct ocfs2_xattr_set_ctxt *ctxt) | ||
2089 | { | 2088 | { |
2089 | int rc = 0; | ||
2090 | int nameval_offset = le16_to_cpu(loc->xl_entry->xe_name_offset); | 2090 | int nameval_offset = le16_to_cpu(loc->xl_entry->xe_name_offset); |
2091 | int name_size = OCFS2_XATTR_SIZE(xi->xi_name_len); | 2091 | int name_size = OCFS2_XATTR_SIZE(xi->xi_name_len); |
2092 | int inline_value_size = namevalue_size_xi(xi) - name_size; | ||
2093 | const void *value = xi->xi_value; | ||
2094 | char *nameval_buf; | 2092 | char *nameval_buf; |
2093 | struct ocfs2_xattr_value_buf vb; | ||
2095 | 2094 | ||
2096 | if (!xi->xi_value) | 2095 | if (!xi->xi_value) |
2097 | return; | 2096 | goto out; |
2098 | 2097 | ||
2099 | if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) { | ||
2100 | value = &def_xv; | ||
2101 | inline_value_size = OCFS2_XATTR_ROOT_SIZE; | ||
2102 | } | ||
2103 | nameval_buf = ocfs2_xa_offset_pointer(loc, nameval_offset); | 2098 | nameval_buf = ocfs2_xa_offset_pointer(loc, nameval_offset); |
2104 | memcpy(nameval_buf + name_size, value, inline_value_size); | 2099 | if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) { |
2100 | ocfs2_xa_fill_value_buf(loc, &vb); | ||
2101 | rc = __ocfs2_xattr_set_value_outside(loc->xl_inode, | ||
2102 | ctxt->handle, &vb, | ||
2103 | xi->xi_value, | ||
2104 | xi->xi_value_len); | ||
2105 | } else | ||
2106 | memcpy(nameval_buf + name_size, xi->xi_value, xi->xi_value_len); | ||
2107 | |||
2108 | out: | ||
2109 | return rc; | ||
2105 | } | 2110 | } |
2106 | 2111 | ||
2107 | static void ocfs2_init_dinode_xa_loc(struct ocfs2_xa_loc *loc, | 2112 | static void ocfs2_init_dinode_xa_loc(struct ocfs2_xa_loc *loc, |
@@ -2174,117 +2179,19 @@ static int ocfs2_xattr_set_entry(struct inode *inode, | |||
2174 | struct ocfs2_xattr_set_ctxt *ctxt, | 2179 | struct ocfs2_xattr_set_ctxt *ctxt, |
2175 | int flag) | 2180 | int flag) |
2176 | { | 2181 | { |
2177 | struct ocfs2_xattr_entry *last; | ||
2178 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | 2182 | struct ocfs2_inode_info *oi = OCFS2_I(inode); |
2179 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; | 2183 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; |
2180 | size_t min_offs = xs->end - xs->base; | ||
2181 | size_t size_l = 0; | ||
2182 | handle_t *handle = ctxt->handle; | 2184 | handle_t *handle = ctxt->handle; |
2183 | int free, i, ret; | 2185 | int ret; |
2184 | u32 name_hash = ocfs2_xattr_name_hash(inode, xi->xi_name, | 2186 | u32 name_hash = ocfs2_xattr_name_hash(inode, xi->xi_name, |
2185 | xi->xi_name_len); | 2187 | xi->xi_name_len); |
2186 | struct ocfs2_xa_loc loc; | 2188 | struct ocfs2_xa_loc loc; |
2187 | struct ocfs2_xattr_value_buf vb = { | ||
2188 | .vb_bh = xs->xattr_bh, | ||
2189 | .vb_access = ocfs2_journal_access_di, | ||
2190 | }; | ||
2191 | 2189 | ||
2192 | if (!(flag & OCFS2_INLINE_XATTR_FL)) { | 2190 | if (!(flag & OCFS2_INLINE_XATTR_FL)) |
2193 | BUG_ON(xs->xattr_bh == xs->inode_bh); | 2191 | BUG_ON(xs->xattr_bh == xs->inode_bh); |
2194 | vb.vb_access = ocfs2_journal_access_xb; | 2192 | else |
2195 | } else | ||
2196 | BUG_ON(xs->xattr_bh != xs->inode_bh); | 2193 | BUG_ON(xs->xattr_bh != xs->inode_bh); |
2197 | 2194 | ||
2198 | /* Compute min_offs, last and free space. */ | ||
2199 | last = xs->header->xh_entries; | ||
2200 | |||
2201 | for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) { | ||
2202 | size_t offs = le16_to_cpu(last->xe_name_offset); | ||
2203 | if (offs < min_offs) | ||
2204 | min_offs = offs; | ||
2205 | last += 1; | ||
2206 | } | ||
2207 | |||
2208 | free = min_offs - ((void *)last - xs->base) - OCFS2_XATTR_HEADER_GAP; | ||
2209 | if (free < 0) | ||
2210 | return -EIO; | ||
2211 | |||
2212 | if (!xs->not_found) | ||
2213 | free += ocfs2_xe_entry_usage(xs->here); | ||
2214 | |||
2215 | /* Check free space in inode or block */ | ||
2216 | if (xi->xi_value && (free < ocfs2_xi_entry_usage(xi))) { | ||
2217 | ret = -ENOSPC; | ||
2218 | goto out; | ||
2219 | } | ||
2220 | |||
2221 | if (!xs->not_found) { | ||
2222 | /* For existing extended attribute */ | ||
2223 | size_t size = namevalue_size_xe(xs->here); | ||
2224 | size_t offs = le16_to_cpu(xs->here->xe_name_offset); | ||
2225 | void *val = xs->base + offs; | ||
2226 | |||
2227 | if (ocfs2_xattr_is_local(xs->here) && size == size_l) { | ||
2228 | /* Replace existing local xattr with tree root */ | ||
2229 | ret = ocfs2_xattr_set_value_outside(inode, xi, xs, | ||
2230 | ctxt, &vb, offs); | ||
2231 | if (ret < 0) | ||
2232 | mlog_errno(ret); | ||
2233 | goto out; | ||
2234 | } else if (!ocfs2_xattr_is_local(xs->here)) { | ||
2235 | /* For existing xattr which has value outside */ | ||
2236 | vb.vb_xv = (struct ocfs2_xattr_value_root *) | ||
2237 | (val + OCFS2_XATTR_SIZE(xi->xi_name_len)); | ||
2238 | |||
2239 | if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) { | ||
2240 | /* | ||
2241 | * If new value need set outside also, | ||
2242 | * first truncate old value to new value, | ||
2243 | * then set new value with set_value_outside(). | ||
2244 | */ | ||
2245 | ret = ocfs2_xattr_value_truncate(inode, | ||
2246 | &vb, | ||
2247 | xi->xi_value_len, | ||
2248 | ctxt); | ||
2249 | if (ret < 0) { | ||
2250 | mlog_errno(ret); | ||
2251 | goto out; | ||
2252 | } | ||
2253 | |||
2254 | ret = ocfs2_xattr_update_entry(inode, | ||
2255 | handle, | ||
2256 | xi, | ||
2257 | xs, | ||
2258 | &vb, | ||
2259 | offs); | ||
2260 | if (ret < 0) { | ||
2261 | mlog_errno(ret); | ||
2262 | goto out; | ||
2263 | } | ||
2264 | |||
2265 | ret = __ocfs2_xattr_set_value_outside(inode, | ||
2266 | handle, | ||
2267 | &vb, | ||
2268 | xi->xi_value, | ||
2269 | xi->xi_value_len); | ||
2270 | if (ret < 0) | ||
2271 | mlog_errno(ret); | ||
2272 | goto out; | ||
2273 | } else { | ||
2274 | /* | ||
2275 | * If new value need set in local, | ||
2276 | * just trucate old value to zero. | ||
2277 | */ | ||
2278 | ret = ocfs2_xattr_value_truncate(inode, | ||
2279 | &vb, | ||
2280 | 0, | ||
2281 | ctxt); | ||
2282 | if (ret < 0) | ||
2283 | mlog_errno(ret); | ||
2284 | } | ||
2285 | } | ||
2286 | } | ||
2287 | |||
2288 | ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), xs->inode_bh, | 2195 | ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), xs->inode_bh, |
2289 | OCFS2_JOURNAL_ACCESS_WRITE); | 2196 | OCFS2_JOURNAL_ACCESS_WRITE); |
2290 | if (ret) { | 2197 | if (ret) { |
@@ -2305,22 +2212,20 @@ static int ocfs2_xattr_set_entry(struct inode *inode, | |||
2305 | goto out; | 2212 | goto out; |
2306 | } | 2213 | } |
2307 | 2214 | ||
2308 | /* | 2215 | ret = ocfs2_xa_prepare_entry(&loc, xi, name_hash, ctxt); |
2309 | * Prepare our entry and insert the inline value. This will | ||
2310 | * be a value tree root for values that are larger than | ||
2311 | * OCFS2_XATTR_INLINE_SIZE. | ||
2312 | */ | ||
2313 | ret = ocfs2_xa_prepare_entry(&loc, xi, name_hash); | ||
2314 | if (ret) { | 2216 | if (ret) { |
2315 | if (ret != -ENOSPC) | 2217 | if (ret != -ENOSPC) |
2316 | mlog_errno(ret); | 2218 | mlog_errno(ret); |
2317 | goto out; | 2219 | goto out; |
2318 | } | 2220 | } |
2319 | /* XXX For now, until we make ocfs2_xa_prepare_entry() primary */ | ||
2320 | BUG_ON(ret == -ENOSPC); | ||
2321 | ocfs2_xa_store_inline_value(&loc, xi); | ||
2322 | xs->here = loc.xl_entry; | 2221 | xs->here = loc.xl_entry; |
2323 | 2222 | ||
2223 | ret = ocfs2_xa_store_value(&loc, xi, ctxt); | ||
2224 | if (ret) { | ||
2225 | mlog_errno(ret); | ||
2226 | goto out; | ||
2227 | } | ||
2228 | |||
2324 | ocfs2_xa_journal_dirty(handle, &loc); | 2229 | ocfs2_xa_journal_dirty(handle, &loc); |
2325 | 2230 | ||
2326 | if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) && | 2231 | if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) && |
@@ -2352,28 +2257,6 @@ static int ocfs2_xattr_set_entry(struct inode *inode, | |||
2352 | if (ret < 0) | 2257 | if (ret < 0) |
2353 | mlog_errno(ret); | 2258 | mlog_errno(ret); |
2354 | 2259 | ||
2355 | if (!ret && xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) { | ||
2356 | /* | ||
2357 | * Set value outside in B tree. | ||
2358 | * This is the second step for value size > INLINE_SIZE. | ||
2359 | */ | ||
2360 | size_t offs = le16_to_cpu(xs->here->xe_name_offset); | ||
2361 | ret = ocfs2_xattr_set_value_outside(inode, xi, xs, ctxt, | ||
2362 | &vb, offs); | ||
2363 | if (ret < 0) { | ||
2364 | int ret2; | ||
2365 | |||
2366 | mlog_errno(ret); | ||
2367 | /* | ||
2368 | * If set value outside failed, we have to clean | ||
2369 | * the junk tree root we have already set in local. | ||
2370 | */ | ||
2371 | ret2 = ocfs2_xattr_cleanup(inode, ctxt->handle, | ||
2372 | xi, xs, &vb, offs); | ||
2373 | if (ret2 < 0) | ||
2374 | mlog_errno(ret2); | ||
2375 | } | ||
2376 | } | ||
2377 | out: | 2260 | out: |
2378 | return ret; | 2261 | return ret; |
2379 | } | 2262 | } |
@@ -5354,61 +5237,6 @@ static inline char *ocfs2_xattr_bucket_get_val(struct inode *inode, | |||
5354 | } | 5237 | } |
5355 | 5238 | ||
5356 | /* | 5239 | /* |
5357 | * Set the xattr entry in the specified bucket. | ||
5358 | * The bucket is indicated by xs->bucket and it should have the enough | ||
5359 | * space for the xattr insertion. | ||
5360 | */ | ||
5361 | static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, | ||
5362 | handle_t *handle, | ||
5363 | struct ocfs2_xattr_info *xi, | ||
5364 | struct ocfs2_xattr_search *xs, | ||
5365 | u32 name_hash) | ||
5366 | { | ||
5367 | int ret; | ||
5368 | u64 blkno; | ||
5369 | struct ocfs2_xa_loc loc; | ||
5370 | |||
5371 | mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n", | ||
5372 | (unsigned long)xi->xi_value_len, xi->xi_name_index, | ||
5373 | (unsigned long long)bucket_blkno(xs->bucket)); | ||
5374 | |||
5375 | if (!xs->bucket->bu_bhs[1]) { | ||
5376 | blkno = bucket_blkno(xs->bucket); | ||
5377 | ocfs2_xattr_bucket_relse(xs->bucket); | ||
5378 | ret = ocfs2_read_xattr_bucket(xs->bucket, blkno); | ||
5379 | if (ret) { | ||
5380 | mlog_errno(ret); | ||
5381 | goto out; | ||
5382 | } | ||
5383 | } | ||
5384 | |||
5385 | ocfs2_init_xattr_bucket_xa_loc(&loc, xs->bucket, | ||
5386 | xs->not_found ? NULL : xs->here); | ||
5387 | ret = ocfs2_xa_journal_access(handle, &loc, | ||
5388 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
5389 | if (ret < 0) { | ||
5390 | mlog_errno(ret); | ||
5391 | goto out; | ||
5392 | } | ||
5393 | |||
5394 | ret = ocfs2_xa_prepare_entry(&loc, xi, name_hash); | ||
5395 | if (ret) { | ||
5396 | if (ret != -ENOSPC) | ||
5397 | mlog_errno(ret); | ||
5398 | goto out; | ||
5399 | } | ||
5400 | /* XXX For now, until we make ocfs2_xa_prepare_entry() primary */ | ||
5401 | BUG_ON(ret == -ENOSPC); | ||
5402 | ocfs2_xa_store_inline_value(&loc, xi); | ||
5403 | xs->here = loc.xl_entry; | ||
5404 | |||
5405 | ocfs2_xa_journal_dirty(handle, &loc); | ||
5406 | |||
5407 | out: | ||
5408 | return ret; | ||
5409 | } | ||
5410 | |||
5411 | /* | ||
5412 | * Truncate the specified xe_off entry in xattr bucket. | 5240 | * Truncate the specified xe_off entry in xattr bucket. |
5413 | * bucket is indicated by header_bh and len is the new length. | 5241 | * bucket is indicated by header_bh and len is the new length. |
5414 | * Both the ocfs2_xattr_value_root and the entry will be updated here. | 5242 | * Both the ocfs2_xattr_value_root and the entry will be updated here. |
@@ -5478,66 +5306,6 @@ out: | |||
5478 | return ret; | 5306 | return ret; |
5479 | } | 5307 | } |
5480 | 5308 | ||
5481 | static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, | ||
5482 | struct ocfs2_xattr_search *xs, | ||
5483 | int len, | ||
5484 | struct ocfs2_xattr_set_ctxt *ctxt) | ||
5485 | { | ||
5486 | int ret, offset; | ||
5487 | struct ocfs2_xattr_entry *xe = xs->here; | ||
5488 | struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)xs->base; | ||
5489 | |||
5490 | BUG_ON(!xs->bucket->bu_bhs[0] || !xe || ocfs2_xattr_is_local(xe)); | ||
5491 | |||
5492 | offset = xe - xh->xh_entries; | ||
5493 | ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket, | ||
5494 | offset, len, ctxt); | ||
5495 | if (ret) | ||
5496 | mlog_errno(ret); | ||
5497 | |||
5498 | return ret; | ||
5499 | } | ||
5500 | |||
5501 | static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode, | ||
5502 | handle_t *handle, | ||
5503 | struct ocfs2_xattr_search *xs, | ||
5504 | char *val, | ||
5505 | int value_len) | ||
5506 | { | ||
5507 | int ret, offset, block_off; | ||
5508 | struct ocfs2_xattr_value_root *xv; | ||
5509 | struct ocfs2_xattr_entry *xe = xs->here; | ||
5510 | struct ocfs2_xattr_header *xh = bucket_xh(xs->bucket); | ||
5511 | void *base; | ||
5512 | struct ocfs2_xattr_value_buf vb = { | ||
5513 | .vb_access = ocfs2_journal_access, | ||
5514 | }; | ||
5515 | |||
5516 | BUG_ON(!xs->base || !xe || ocfs2_xattr_is_local(xe)); | ||
5517 | |||
5518 | ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb, xh, | ||
5519 | xe - xh->xh_entries, | ||
5520 | &block_off, | ||
5521 | &offset); | ||
5522 | if (ret) { | ||
5523 | mlog_errno(ret); | ||
5524 | goto out; | ||
5525 | } | ||
5526 | |||
5527 | base = bucket_block(xs->bucket, block_off); | ||
5528 | xv = (struct ocfs2_xattr_value_root *)(base + offset + | ||
5529 | OCFS2_XATTR_SIZE(xe->xe_name_len)); | ||
5530 | |||
5531 | vb.vb_xv = xv; | ||
5532 | vb.vb_bh = xs->bucket->bu_bhs[block_off]; | ||
5533 | ret = __ocfs2_xattr_set_value_outside(inode, handle, | ||
5534 | &vb, val, value_len); | ||
5535 | if (ret) | ||
5536 | mlog_errno(ret); | ||
5537 | out: | ||
5538 | return ret; | ||
5539 | } | ||
5540 | |||
5541 | static int ocfs2_rm_xattr_cluster(struct inode *inode, | 5309 | static int ocfs2_rm_xattr_cluster(struct inode *inode, |
5542 | struct buffer_head *root_bh, | 5310 | struct buffer_head *root_bh, |
5543 | u64 blkno, | 5311 | u64 blkno, |
@@ -5636,41 +5404,8 @@ out: | |||
5636 | return ret; | 5404 | return ret; |
5637 | } | 5405 | } |
5638 | 5406 | ||
5639 | static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, | ||
5640 | handle_t *handle, | ||
5641 | struct ocfs2_xattr_search *xs) | ||
5642 | { | ||
5643 | struct ocfs2_xattr_header *xh = bucket_xh(xs->bucket); | ||
5644 | struct ocfs2_xattr_entry *last = &xh->xh_entries[ | ||
5645 | le16_to_cpu(xh->xh_count) - 1]; | ||
5646 | int ret = 0; | ||
5647 | |||
5648 | ret = ocfs2_xattr_bucket_journal_access(handle, xs->bucket, | ||
5649 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
5650 | if (ret) { | ||
5651 | mlog_errno(ret); | ||
5652 | return; | ||
5653 | } | ||
5654 | |||
5655 | /* Remove the old entry. */ | ||
5656 | memmove(xs->here, xs->here + 1, | ||
5657 | (void *)last - (void *)xs->here); | ||
5658 | memset(last, 0, sizeof(struct ocfs2_xattr_entry)); | ||
5659 | le16_add_cpu(&xh->xh_count, -1); | ||
5660 | |||
5661 | ocfs2_xattr_bucket_journal_dirty(handle, xs->bucket); | ||
5662 | } | ||
5663 | |||
5664 | /* | 5407 | /* |
5665 | * Set the xattr name/value in the bucket specified in xs. | 5408 | * Set the xattr name/value in the bucket specified in xs. |
5666 | * | ||
5667 | * As the new value in xi may be stored in the bucket or in an outside cluster, | ||
5668 | * we divide the whole process into 3 steps: | ||
5669 | * 1. insert name/value in the bucket(ocfs2_xattr_set_entry_in_bucket) | ||
5670 | * 2. truncate of the outside cluster(ocfs2_xattr_bucket_value_truncate_xs) | ||
5671 | * 3. Set the value to the outside cluster(ocfs2_xattr_bucket_set_value_outside) | ||
5672 | * 4. If the clusters for the new outside value can't be allocated, we need | ||
5673 | * to free the xattr we allocated in set. | ||
5674 | */ | 5409 | */ |
5675 | static int ocfs2_xattr_set_in_bucket(struct inode *inode, | 5410 | static int ocfs2_xattr_set_in_bucket(struct inode *inode, |
5676 | struct ocfs2_xattr_info *xi, | 5411 | struct ocfs2_xattr_info *xi, |
@@ -5678,70 +5413,46 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode, | |||
5678 | struct ocfs2_xattr_set_ctxt *ctxt) | 5413 | struct ocfs2_xattr_set_ctxt *ctxt) |
5679 | { | 5414 | { |
5680 | int ret; | 5415 | int ret; |
5681 | size_t value_len; | 5416 | u64 blkno; |
5682 | char *val = (char *)xi->xi_value; | 5417 | struct ocfs2_xa_loc loc; |
5683 | struct ocfs2_xattr_entry *xe = xs->here; | ||
5684 | u32 name_hash = ocfs2_xattr_name_hash(inode, xi->xi_name, | 5418 | u32 name_hash = ocfs2_xattr_name_hash(inode, xi->xi_name, |
5685 | xi->xi_name_len); | 5419 | xi->xi_name_len); |
5686 | 5420 | ||
5687 | value_len = xi->xi_value_len; | 5421 | if (!xs->bucket->bu_bhs[1]) { |
5688 | if (!xs->not_found && !ocfs2_xattr_is_local(xe)) { | 5422 | blkno = bucket_blkno(xs->bucket); |
5689 | /* | 5423 | ocfs2_xattr_bucket_relse(xs->bucket); |
5690 | * We need to truncate the xattr storage first. | 5424 | ret = ocfs2_read_xattr_bucket(xs->bucket, blkno); |
5691 | * | 5425 | if (ret) { |
5692 | * If both the old and new value are stored to | 5426 | mlog_errno(ret); |
5693 | * outside block, we only need to truncate | ||
5694 | * the storage and then set the value outside. | ||
5695 | * | ||
5696 | * If the new value should be stored within block, | ||
5697 | * we should free all the outside block first and | ||
5698 | * the modification to the xattr block will be done | ||
5699 | * by following steps. | ||
5700 | */ | ||
5701 | if (xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE) | ||
5702 | value_len = 0; | ||
5703 | |||
5704 | ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, | ||
5705 | value_len, | ||
5706 | ctxt); | ||
5707 | if (ret) | ||
5708 | goto out; | 5427 | goto out; |
5709 | 5428 | } | |
5710 | if (value_len) | ||
5711 | goto set_value_outside; | ||
5712 | } | 5429 | } |
5713 | 5430 | ||
5714 | /* So we have to handle the inside block change now. */ | 5431 | ocfs2_init_xattr_bucket_xa_loc(&loc, xs->bucket, |
5715 | ret = ocfs2_xattr_set_entry_in_bucket(inode, ctxt->handle, xi, xs, | 5432 | xs->not_found ? NULL : xs->here); |
5716 | name_hash); | 5433 | ret = ocfs2_xa_journal_access(ctxt->handle, &loc, |
5717 | if (ret) { | 5434 | OCFS2_JOURNAL_ACCESS_WRITE); |
5435 | if (ret < 0) { | ||
5718 | mlog_errno(ret); | 5436 | mlog_errno(ret); |
5719 | goto out; | 5437 | goto out; |
5720 | } | 5438 | } |
5721 | 5439 | ||
5722 | if (xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE) | 5440 | ret = ocfs2_xa_prepare_entry(&loc, xi, name_hash, ctxt); |
5441 | if (ret) { | ||
5442 | if (ret != -ENOSPC) | ||
5443 | mlog_errno(ret); | ||
5723 | goto out; | 5444 | goto out; |
5445 | } | ||
5446 | xs->here = loc.xl_entry; | ||
5724 | 5447 | ||
5725 | /* allocate the space now for the outside block storage. */ | 5448 | ret = ocfs2_xa_store_value(&loc, xi, ctxt); |
5726 | ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, | ||
5727 | value_len, ctxt); | ||
5728 | if (ret) { | 5449 | if (ret) { |
5729 | mlog_errno(ret); | 5450 | mlog_errno(ret); |
5730 | |||
5731 | if (xs->not_found) { | ||
5732 | /* | ||
5733 | * We can't allocate enough clusters for outside | ||
5734 | * storage and we have allocated xattr already, | ||
5735 | * so need to remove it. | ||
5736 | */ | ||
5737 | ocfs2_xattr_bucket_remove_xs(inode, ctxt->handle, xs); | ||
5738 | } | ||
5739 | goto out; | 5451 | goto out; |
5740 | } | 5452 | } |
5741 | 5453 | ||
5742 | set_value_outside: | 5454 | ocfs2_xa_journal_dirty(ctxt->handle, &loc); |
5743 | ret = ocfs2_xattr_bucket_set_value_outside(inode, ctxt->handle, | 5455 | |
5744 | xs, val, value_len); | ||
5745 | out: | 5456 | out: |
5746 | return ret; | 5457 | return ret; |
5747 | } | 5458 | } |