diff options
Diffstat (limited to 'fs/ocfs2/xattr.c')
-rw-r--r-- | fs/ocfs2/xattr.c | 140 |
1 files changed, 124 insertions, 16 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index a2d912a92dd7..d1b0d386f6d1 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -1869,6 +1869,17 @@ static const struct ocfs2_xa_loc_operations ocfs2_xa_bucket_loc_ops = { | |||
1869 | .xlo_fill_value_buf = ocfs2_xa_bucket_fill_value_buf, | 1869 | .xlo_fill_value_buf = ocfs2_xa_bucket_fill_value_buf, |
1870 | }; | 1870 | }; |
1871 | 1871 | ||
1872 | static unsigned int ocfs2_xa_value_clusters(struct ocfs2_xa_loc *loc) | ||
1873 | { | ||
1874 | struct ocfs2_xattr_value_buf vb; | ||
1875 | |||
1876 | if (ocfs2_xattr_is_local(loc->xl_entry)) | ||
1877 | return 0; | ||
1878 | |||
1879 | ocfs2_xa_fill_value_buf(loc, &vb); | ||
1880 | return le32_to_cpu(vb.vb_xv->xr_clusters); | ||
1881 | } | ||
1882 | |||
1872 | static int ocfs2_xa_value_truncate(struct ocfs2_xa_loc *loc, u64 bytes, | 1883 | static int ocfs2_xa_value_truncate(struct ocfs2_xa_loc *loc, u64 bytes, |
1873 | struct ocfs2_xattr_set_ctxt *ctxt) | 1884 | struct ocfs2_xattr_set_ctxt *ctxt) |
1874 | { | 1885 | { |
@@ -1923,16 +1934,85 @@ static void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc) | |||
1923 | } | 1934 | } |
1924 | } | 1935 | } |
1925 | 1936 | ||
1937 | /* | ||
1938 | * If we have a problem adjusting the size of an external value during | ||
1939 | * ocfs2_xa_prepare_entry() or ocfs2_xa_remove(), we may have an xattr | ||
1940 | * in an intermediate state. For example, the value may be partially | ||
1941 | * truncated. | ||
1942 | * | ||
1943 | * If the value tree hasn't changed, the extend/truncate went nowhere. | ||
1944 | * We have nothing to do. The caller can treat it as a straight error. | ||
1945 | * | ||
1946 | * If the value tree got partially truncated, we now have a corrupted | ||
1947 | * extended attribute. We're going to wipe its entry and leak the | ||
1948 | * clusters. Better to leak some storage than leave a corrupt entry. | ||
1949 | * | ||
1950 | * If the value tree grew, it obviously didn't grow enough for the | ||
1951 | * new entry. We're not going to try and reclaim those clusters either. | ||
1952 | * If there was already an external value there (orig_clusters != 0), | ||
1953 | * the new clusters are attached safely and we can just leave the old | ||
1954 | * value in place. If there was no external value there, we remove | ||
1955 | * the entry. | ||
1956 | * | ||
1957 | * This way, the xattr block we store in the journal will be consistent. | ||
1958 | * If the size change broke because of the journal, no changes will hit | ||
1959 | * disk anyway. | ||
1960 | */ | ||
1961 | static void ocfs2_xa_cleanup_value_truncate(struct ocfs2_xa_loc *loc, | ||
1962 | const char *what, | ||
1963 | unsigned int orig_clusters) | ||
1964 | { | ||
1965 | unsigned int new_clusters = ocfs2_xa_value_clusters(loc); | ||
1966 | char *nameval_buf = ocfs2_xa_offset_pointer(loc, | ||
1967 | le16_to_cpu(loc->xl_entry->xe_name_offset)); | ||
1968 | |||
1969 | if (new_clusters < orig_clusters) { | ||
1970 | mlog(ML_ERROR, | ||
1971 | "Partial truncate while %s xattr %.*s. Leaking " | ||
1972 | "%u clusters and removing the entry\n", | ||
1973 | what, loc->xl_entry->xe_name_len, nameval_buf, | ||
1974 | orig_clusters - new_clusters); | ||
1975 | ocfs2_xa_remove_entry(loc); | ||
1976 | } else if (!orig_clusters) { | ||
1977 | mlog(ML_ERROR, | ||
1978 | "Unable to allocate an external value for xattr " | ||
1979 | "%.*s safely. Leaking %u clusters and removing the " | ||
1980 | "entry\n", | ||
1981 | loc->xl_entry->xe_name_len, nameval_buf, | ||
1982 | new_clusters - orig_clusters); | ||
1983 | ocfs2_xa_remove_entry(loc); | ||
1984 | } else if (new_clusters > orig_clusters) | ||
1985 | mlog(ML_ERROR, | ||
1986 | "Unable to grow xattr %.*s safely. %u new clusters " | ||
1987 | "have been added, but the value will not be " | ||
1988 | "modified\n", | ||
1989 | loc->xl_entry->xe_name_len, nameval_buf, | ||
1990 | new_clusters - orig_clusters); | ||
1991 | } | ||
1992 | |||
1926 | static int ocfs2_xa_remove(struct ocfs2_xa_loc *loc, | 1993 | static int ocfs2_xa_remove(struct ocfs2_xa_loc *loc, |
1927 | struct ocfs2_xattr_set_ctxt *ctxt) | 1994 | struct ocfs2_xattr_set_ctxt *ctxt) |
1928 | { | 1995 | { |
1929 | int rc = 0; | 1996 | int rc = 0; |
1997 | unsigned int orig_clusters; | ||
1930 | 1998 | ||
1931 | if (!ocfs2_xattr_is_local(loc->xl_entry)) { | 1999 | if (!ocfs2_xattr_is_local(loc->xl_entry)) { |
2000 | orig_clusters = ocfs2_xa_value_clusters(loc); | ||
1932 | rc = ocfs2_xa_value_truncate(loc, 0, ctxt); | 2001 | rc = ocfs2_xa_value_truncate(loc, 0, ctxt); |
1933 | if (rc) { | 2002 | if (rc) { |
1934 | mlog_errno(rc); | 2003 | mlog_errno(rc); |
1935 | goto out; | 2004 | /* |
2005 | * Since this is remove, we can return 0 if | ||
2006 | * ocfs2_xa_cleanup_value_truncate() is going to | ||
2007 | * wipe the entry anyway. So we check the | ||
2008 | * cluster count as well. | ||
2009 | */ | ||
2010 | if (orig_clusters != ocfs2_xa_value_clusters(loc)) | ||
2011 | rc = 0; | ||
2012 | ocfs2_xa_cleanup_value_truncate(loc, "removing", | ||
2013 | orig_clusters); | ||
2014 | if (rc) | ||
2015 | goto out; | ||
1936 | } | 2016 | } |
1937 | } | 2017 | } |
1938 | 2018 | ||
@@ -1963,6 +2043,7 @@ static int ocfs2_xa_reuse_entry(struct ocfs2_xa_loc *loc, | |||
1963 | { | 2043 | { |
1964 | int rc = 0; | 2044 | int rc = 0; |
1965 | int name_size = OCFS2_XATTR_SIZE(xi->xi_name_len); | 2045 | int name_size = OCFS2_XATTR_SIZE(xi->xi_name_len); |
2046 | unsigned int orig_clusters; | ||
1966 | char *nameval_buf; | 2047 | char *nameval_buf; |
1967 | int xe_local = ocfs2_xattr_is_local(loc->xl_entry); | 2048 | int xe_local = ocfs2_xattr_is_local(loc->xl_entry); |
1968 | int xi_local = xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE; | 2049 | int xi_local = xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE; |
@@ -1978,23 +2059,27 @@ static int ocfs2_xa_reuse_entry(struct ocfs2_xa_loc *loc, | |||
1978 | if (!xi_local) | 2059 | if (!xi_local) |
1979 | ocfs2_xa_install_value_root(loc); | 2060 | ocfs2_xa_install_value_root(loc); |
1980 | } else { | 2061 | } else { |
2062 | orig_clusters = ocfs2_xa_value_clusters(loc); | ||
1981 | if (xi_local) { | 2063 | if (xi_local) { |
1982 | rc = ocfs2_xa_value_truncate(loc, 0, ctxt); | 2064 | rc = ocfs2_xa_value_truncate(loc, 0, ctxt); |
1983 | if (rc < 0) { | 2065 | if (rc < 0) |
1984 | mlog_errno(rc); | 2066 | mlog_errno(rc); |
1985 | goto out; | 2067 | else |
1986 | } | 2068 | memset(nameval_buf + name_size, 0, |
1987 | memset(nameval_buf + name_size, 0, | 2069 | namevalue_size_xe(loc->xl_entry) - |
1988 | namevalue_size_xe(loc->xl_entry) - | 2070 | name_size); |
1989 | name_size); | ||
1990 | } else if (le64_to_cpu(loc->xl_entry->xe_value_size) > | 2071 | } else if (le64_to_cpu(loc->xl_entry->xe_value_size) > |
1991 | xi->xi_value_len) { | 2072 | xi->xi_value_len) { |
1992 | rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len, | 2073 | rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len, |
1993 | ctxt); | 2074 | ctxt); |
1994 | if (rc < 0) { | 2075 | if (rc < 0) |
1995 | mlog_errno(rc); | 2076 | mlog_errno(rc); |
1996 | goto out; | 2077 | } |
1997 | } | 2078 | |
2079 | if (rc) { | ||
2080 | ocfs2_xa_cleanup_value_truncate(loc, "reusing", | ||
2081 | orig_clusters); | ||
2082 | goto out; | ||
1998 | } | 2083 | } |
1999 | } | 2084 | } |
2000 | 2085 | ||
@@ -2019,6 +2104,8 @@ static int ocfs2_xa_prepare_entry(struct ocfs2_xa_loc *loc, | |||
2019 | struct ocfs2_xattr_set_ctxt *ctxt) | 2104 | struct ocfs2_xattr_set_ctxt *ctxt) |
2020 | { | 2105 | { |
2021 | int rc = 0; | 2106 | int rc = 0; |
2107 | unsigned int orig_clusters; | ||
2108 | __le64 orig_value_size = 0; | ||
2022 | 2109 | ||
2023 | rc = ocfs2_xa_check_space(loc, xi); | 2110 | rc = ocfs2_xa_check_space(loc, xi); |
2024 | if (rc) | 2111 | if (rc) |
@@ -2026,6 +2113,7 @@ static int ocfs2_xa_prepare_entry(struct ocfs2_xa_loc *loc, | |||
2026 | 2113 | ||
2027 | if (loc->xl_entry) { | 2114 | if (loc->xl_entry) { |
2028 | if (ocfs2_xa_can_reuse_entry(loc, xi)) { | 2115 | if (ocfs2_xa_can_reuse_entry(loc, xi)) { |
2116 | orig_value_size = loc->xl_entry->xe_value_size; | ||
2029 | rc = ocfs2_xa_reuse_entry(loc, xi, ctxt); | 2117 | rc = ocfs2_xa_reuse_entry(loc, xi, ctxt); |
2030 | if (rc) | 2118 | if (rc) |
2031 | goto out; | 2119 | goto out; |
@@ -2033,9 +2121,13 @@ static int ocfs2_xa_prepare_entry(struct ocfs2_xa_loc *loc, | |||
2033 | } | 2121 | } |
2034 | 2122 | ||
2035 | if (!ocfs2_xattr_is_local(loc->xl_entry)) { | 2123 | if (!ocfs2_xattr_is_local(loc->xl_entry)) { |
2124 | orig_clusters = ocfs2_xa_value_clusters(loc); | ||
2036 | rc = ocfs2_xa_value_truncate(loc, 0, ctxt); | 2125 | rc = ocfs2_xa_value_truncate(loc, 0, ctxt); |
2037 | if (rc) { | 2126 | if (rc) { |
2038 | mlog_errno(rc); | 2127 | mlog_errno(rc); |
2128 | ocfs2_xa_cleanup_value_truncate(loc, | ||
2129 | "overwriting", | ||
2130 | orig_clusters); | ||
2039 | goto out; | 2131 | goto out; |
2040 | } | 2132 | } |
2041 | } | 2133 | } |
@@ -2053,9 +2145,20 @@ static int ocfs2_xa_prepare_entry(struct ocfs2_xa_loc *loc, | |||
2053 | 2145 | ||
2054 | alloc_value: | 2146 | alloc_value: |
2055 | if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) { | 2147 | if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) { |
2148 | orig_clusters = ocfs2_xa_value_clusters(loc); | ||
2056 | rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len, ctxt); | 2149 | rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len, ctxt); |
2057 | if (rc < 0) | 2150 | if (rc < 0) { |
2151 | /* | ||
2152 | * If we tried to grow an existing external value, | ||
2153 | * ocfs2_xa_cleanuP-value_truncate() is going to | ||
2154 | * let it stand. We have to restore its original | ||
2155 | * value size. | ||
2156 | */ | ||
2157 | loc->xl_entry->xe_value_size = orig_value_size; | ||
2158 | ocfs2_xa_cleanup_value_truncate(loc, "growing", | ||
2159 | orig_clusters); | ||
2058 | mlog_errno(rc); | 2160 | mlog_errno(rc); |
2161 | } | ||
2059 | } | 2162 | } |
2060 | 2163 | ||
2061 | out: | 2164 | out: |
@@ -2105,25 +2208,30 @@ static int ocfs2_xa_set(struct ocfs2_xa_loc *loc, | |||
2105 | goto out; | 2208 | goto out; |
2106 | } | 2209 | } |
2107 | 2210 | ||
2211 | /* | ||
2212 | * From here on out, everything is going to modify the buffer a | ||
2213 | * little. Errors are going to leave the xattr header in a | ||
2214 | * sane state. Thus, even with errors we dirty the sucker. | ||
2215 | */ | ||
2216 | |||
2108 | /* Don't worry, we are never called with !xi_value and !xl_entry */ | 2217 | /* Don't worry, we are never called with !xi_value and !xl_entry */ |
2109 | if (!xi->xi_value) { | 2218 | if (!xi->xi_value) { |
2110 | ret = ocfs2_xa_remove(loc, ctxt); | 2219 | ret = ocfs2_xa_remove(loc, ctxt); |
2111 | goto out; | 2220 | goto out_dirty; |
2112 | } | 2221 | } |
2113 | 2222 | ||
2114 | ret = ocfs2_xa_prepare_entry(loc, xi, name_hash, ctxt); | 2223 | ret = ocfs2_xa_prepare_entry(loc, xi, name_hash, ctxt); |
2115 | if (ret) { | 2224 | if (ret) { |
2116 | if (ret != -ENOSPC) | 2225 | if (ret != -ENOSPC) |
2117 | mlog_errno(ret); | 2226 | mlog_errno(ret); |
2118 | goto out; | 2227 | goto out_dirty; |
2119 | } | 2228 | } |
2120 | 2229 | ||
2121 | ret = ocfs2_xa_store_value(loc, xi, ctxt); | 2230 | ret = ocfs2_xa_store_value(loc, xi, ctxt); |
2122 | if (ret) { | 2231 | if (ret) |
2123 | mlog_errno(ret); | 2232 | mlog_errno(ret); |
2124 | goto out; | ||
2125 | } | ||
2126 | 2233 | ||
2234 | out_dirty: | ||
2127 | ocfs2_xa_journal_dirty(ctxt->handle, loc); | 2235 | ocfs2_xa_journal_dirty(ctxt->handle, loc); |
2128 | 2236 | ||
2129 | out: | 2237 | out: |