diff options
-rw-r--r-- | fs/xfs/Makefile | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_attr.c | 298 | ||||
-rw-r--r-- | fs/xfs/xfs_attr.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_attr_leaf.c | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_attr_remote.c | 328 | ||||
-rw-r--r-- | fs/xfs/xfs_attr_remote.h | 25 |
6 files changed, 356 insertions, 298 deletions
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 062f25cd6087..6313b69b6644 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile | |||
@@ -58,6 +58,7 @@ xfs-y += xfs_alloc.o \ | |||
58 | xfs_alloc_btree.o \ | 58 | xfs_alloc_btree.o \ |
59 | xfs_attr.o \ | 59 | xfs_attr.o \ |
60 | xfs_attr_leaf.o \ | 60 | xfs_attr_leaf.o \ |
61 | xfs_attr_remote.o \ | ||
61 | xfs_bmap.o \ | 62 | xfs_bmap.o \ |
62 | xfs_bmap_btree.o \ | 63 | xfs_bmap_btree.o \ |
63 | xfs_btree.o \ | 64 | xfs_btree.o \ |
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index e70687541592..20fe3fe9d341 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "xfs_bmap.h" | 34 | #include "xfs_bmap.h" |
35 | #include "xfs_attr.h" | 35 | #include "xfs_attr.h" |
36 | #include "xfs_attr_leaf.h" | 36 | #include "xfs_attr_leaf.h" |
37 | #include "xfs_attr_remote.h" | ||
37 | #include "xfs_error.h" | 38 | #include "xfs_error.h" |
38 | #include "xfs_quota.h" | 39 | #include "xfs_quota.h" |
39 | #include "xfs_trans_space.h" | 40 | #include "xfs_trans_space.h" |
@@ -73,13 +74,6 @@ STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context); | |||
73 | STATIC int xfs_attr_fillstate(xfs_da_state_t *state); | 74 | STATIC int xfs_attr_fillstate(xfs_da_state_t *state); |
74 | STATIC int xfs_attr_refillstate(xfs_da_state_t *state); | 75 | STATIC int xfs_attr_refillstate(xfs_da_state_t *state); |
75 | 76 | ||
76 | /* | ||
77 | * Routines to manipulate out-of-line attribute values. | ||
78 | */ | ||
79 | STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args); | ||
80 | STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); | ||
81 | |||
82 | #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ | ||
83 | 77 | ||
84 | STATIC int | 78 | STATIC int |
85 | xfs_attr_name_to_xname( | 79 | xfs_attr_name_to_xname( |
@@ -1926,293 +1920,3 @@ xfs_attr_node_list(xfs_attr_list_context_t *context) | |||
1926 | xfs_trans_brelse(NULL, bp); | 1920 | xfs_trans_brelse(NULL, bp); |
1927 | return 0; | 1921 | return 0; |
1928 | } | 1922 | } |
1929 | |||
1930 | |||
1931 | /*======================================================================== | ||
1932 | * External routines for manipulating out-of-line attribute values. | ||
1933 | *========================================================================*/ | ||
1934 | |||
1935 | /* | ||
1936 | * Read the value associated with an attribute from the out-of-line buffer | ||
1937 | * that we stored it in. | ||
1938 | */ | ||
1939 | int | ||
1940 | xfs_attr_rmtval_get(xfs_da_args_t *args) | ||
1941 | { | ||
1942 | xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; | ||
1943 | xfs_mount_t *mp; | ||
1944 | xfs_daddr_t dblkno; | ||
1945 | void *dst; | ||
1946 | xfs_buf_t *bp; | ||
1947 | int nmap, error, tmp, valuelen, blkcnt, i; | ||
1948 | xfs_dablk_t lblkno; | ||
1949 | |||
1950 | trace_xfs_attr_rmtval_get(args); | ||
1951 | |||
1952 | ASSERT(!(args->flags & ATTR_KERNOVAL)); | ||
1953 | |||
1954 | mp = args->dp->i_mount; | ||
1955 | dst = args->value; | ||
1956 | valuelen = args->valuelen; | ||
1957 | lblkno = args->rmtblkno; | ||
1958 | while (valuelen > 0) { | ||
1959 | nmap = ATTR_RMTVALUE_MAPSIZE; | ||
1960 | error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, | ||
1961 | args->rmtblkcnt, map, &nmap, | ||
1962 | XFS_BMAPI_ATTRFORK); | ||
1963 | if (error) | ||
1964 | return(error); | ||
1965 | ASSERT(nmap >= 1); | ||
1966 | |||
1967 | for (i = 0; (i < nmap) && (valuelen > 0); i++) { | ||
1968 | ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && | ||
1969 | (map[i].br_startblock != HOLESTARTBLOCK)); | ||
1970 | dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); | ||
1971 | blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); | ||
1972 | error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, | ||
1973 | dblkno, blkcnt, 0, &bp, NULL); | ||
1974 | if (error) | ||
1975 | return(error); | ||
1976 | |||
1977 | tmp = min_t(int, valuelen, BBTOB(bp->b_length)); | ||
1978 | xfs_buf_iomove(bp, 0, tmp, dst, XBRW_READ); | ||
1979 | xfs_buf_relse(bp); | ||
1980 | dst += tmp; | ||
1981 | valuelen -= tmp; | ||
1982 | |||
1983 | lblkno += map[i].br_blockcount; | ||
1984 | } | ||
1985 | } | ||
1986 | ASSERT(valuelen == 0); | ||
1987 | return(0); | ||
1988 | } | ||
1989 | |||
1990 | /* | ||
1991 | * Write the value associated with an attribute into the out-of-line buffer | ||
1992 | * that we have defined for it. | ||
1993 | */ | ||
1994 | STATIC int | ||
1995 | xfs_attr_rmtval_set(xfs_da_args_t *args) | ||
1996 | { | ||
1997 | xfs_mount_t *mp; | ||
1998 | xfs_fileoff_t lfileoff; | ||
1999 | xfs_inode_t *dp; | ||
2000 | xfs_bmbt_irec_t map; | ||
2001 | xfs_daddr_t dblkno; | ||
2002 | void *src; | ||
2003 | xfs_buf_t *bp; | ||
2004 | xfs_dablk_t lblkno; | ||
2005 | int blkcnt, valuelen, nmap, error, tmp, committed; | ||
2006 | |||
2007 | trace_xfs_attr_rmtval_set(args); | ||
2008 | |||
2009 | dp = args->dp; | ||
2010 | mp = dp->i_mount; | ||
2011 | src = args->value; | ||
2012 | |||
2013 | /* | ||
2014 | * Find a "hole" in the attribute address space large enough for | ||
2015 | * us to drop the new attribute's value into. | ||
2016 | */ | ||
2017 | blkcnt = XFS_B_TO_FSB(mp, args->valuelen); | ||
2018 | lfileoff = 0; | ||
2019 | error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, | ||
2020 | XFS_ATTR_FORK); | ||
2021 | if (error) { | ||
2022 | return(error); | ||
2023 | } | ||
2024 | args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; | ||
2025 | args->rmtblkcnt = blkcnt; | ||
2026 | |||
2027 | /* | ||
2028 | * Roll through the "value", allocating blocks on disk as required. | ||
2029 | */ | ||
2030 | while (blkcnt > 0) { | ||
2031 | /* | ||
2032 | * Allocate a single extent, up to the size of the value. | ||
2033 | */ | ||
2034 | xfs_bmap_init(args->flist, args->firstblock); | ||
2035 | nmap = 1; | ||
2036 | error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno, | ||
2037 | blkcnt, | ||
2038 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, | ||
2039 | args->firstblock, args->total, &map, &nmap, | ||
2040 | args->flist); | ||
2041 | if (!error) { | ||
2042 | error = xfs_bmap_finish(&args->trans, args->flist, | ||
2043 | &committed); | ||
2044 | } | ||
2045 | if (error) { | ||
2046 | ASSERT(committed); | ||
2047 | args->trans = NULL; | ||
2048 | xfs_bmap_cancel(args->flist); | ||
2049 | return(error); | ||
2050 | } | ||
2051 | |||
2052 | /* | ||
2053 | * bmap_finish() may have committed the last trans and started | ||
2054 | * a new one. We need the inode to be in all transactions. | ||
2055 | */ | ||
2056 | if (committed) | ||
2057 | xfs_trans_ijoin(args->trans, dp, 0); | ||
2058 | |||
2059 | ASSERT(nmap == 1); | ||
2060 | ASSERT((map.br_startblock != DELAYSTARTBLOCK) && | ||
2061 | (map.br_startblock != HOLESTARTBLOCK)); | ||
2062 | lblkno += map.br_blockcount; | ||
2063 | blkcnt -= map.br_blockcount; | ||
2064 | |||
2065 | /* | ||
2066 | * Start the next trans in the chain. | ||
2067 | */ | ||
2068 | error = xfs_trans_roll(&args->trans, dp); | ||
2069 | if (error) | ||
2070 | return (error); | ||
2071 | } | ||
2072 | |||
2073 | /* | ||
2074 | * Roll through the "value", copying the attribute value to the | ||
2075 | * already-allocated blocks. Blocks are written synchronously | ||
2076 | * so that we can know they are all on disk before we turn off | ||
2077 | * the INCOMPLETE flag. | ||
2078 | */ | ||
2079 | lblkno = args->rmtblkno; | ||
2080 | valuelen = args->valuelen; | ||
2081 | while (valuelen > 0) { | ||
2082 | int buflen; | ||
2083 | |||
2084 | /* | ||
2085 | * Try to remember where we decided to put the value. | ||
2086 | */ | ||
2087 | xfs_bmap_init(args->flist, args->firstblock); | ||
2088 | nmap = 1; | ||
2089 | error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, | ||
2090 | args->rmtblkcnt, &map, &nmap, | ||
2091 | XFS_BMAPI_ATTRFORK); | ||
2092 | if (error) | ||
2093 | return(error); | ||
2094 | ASSERT(nmap == 1); | ||
2095 | ASSERT((map.br_startblock != DELAYSTARTBLOCK) && | ||
2096 | (map.br_startblock != HOLESTARTBLOCK)); | ||
2097 | |||
2098 | dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), | ||
2099 | blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); | ||
2100 | |||
2101 | bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt, 0); | ||
2102 | if (!bp) | ||
2103 | return ENOMEM; | ||
2104 | |||
2105 | buflen = BBTOB(bp->b_length); | ||
2106 | tmp = min_t(int, valuelen, buflen); | ||
2107 | xfs_buf_iomove(bp, 0, tmp, src, XBRW_WRITE); | ||
2108 | if (tmp < buflen) | ||
2109 | xfs_buf_zero(bp, tmp, buflen - tmp); | ||
2110 | |||
2111 | error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ | ||
2112 | xfs_buf_relse(bp); | ||
2113 | if (error) | ||
2114 | return error; | ||
2115 | src += tmp; | ||
2116 | valuelen -= tmp; | ||
2117 | |||
2118 | lblkno += map.br_blockcount; | ||
2119 | } | ||
2120 | ASSERT(valuelen == 0); | ||
2121 | return(0); | ||
2122 | } | ||
2123 | |||
2124 | /* | ||
2125 | * Remove the value associated with an attribute by deleting the | ||
2126 | * out-of-line buffer that it is stored on. | ||
2127 | */ | ||
2128 | STATIC int | ||
2129 | xfs_attr_rmtval_remove(xfs_da_args_t *args) | ||
2130 | { | ||
2131 | xfs_mount_t *mp; | ||
2132 | xfs_bmbt_irec_t map; | ||
2133 | xfs_buf_t *bp; | ||
2134 | xfs_daddr_t dblkno; | ||
2135 | xfs_dablk_t lblkno; | ||
2136 | int valuelen, blkcnt, nmap, error, done, committed; | ||
2137 | |||
2138 | trace_xfs_attr_rmtval_remove(args); | ||
2139 | |||
2140 | mp = args->dp->i_mount; | ||
2141 | |||
2142 | /* | ||
2143 | * Roll through the "value", invalidating the attribute value's | ||
2144 | * blocks. | ||
2145 | */ | ||
2146 | lblkno = args->rmtblkno; | ||
2147 | valuelen = args->rmtblkcnt; | ||
2148 | while (valuelen > 0) { | ||
2149 | /* | ||
2150 | * Try to remember where we decided to put the value. | ||
2151 | */ | ||
2152 | nmap = 1; | ||
2153 | error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, | ||
2154 | args->rmtblkcnt, &map, &nmap, | ||
2155 | XFS_BMAPI_ATTRFORK); | ||
2156 | if (error) | ||
2157 | return(error); | ||
2158 | ASSERT(nmap == 1); | ||
2159 | ASSERT((map.br_startblock != DELAYSTARTBLOCK) && | ||
2160 | (map.br_startblock != HOLESTARTBLOCK)); | ||
2161 | |||
2162 | dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), | ||
2163 | blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); | ||
2164 | |||
2165 | /* | ||
2166 | * If the "remote" value is in the cache, remove it. | ||
2167 | */ | ||
2168 | bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, XBF_TRYLOCK); | ||
2169 | if (bp) { | ||
2170 | xfs_buf_stale(bp); | ||
2171 | xfs_buf_relse(bp); | ||
2172 | bp = NULL; | ||
2173 | } | ||
2174 | |||
2175 | valuelen -= map.br_blockcount; | ||
2176 | |||
2177 | lblkno += map.br_blockcount; | ||
2178 | } | ||
2179 | |||
2180 | /* | ||
2181 | * Keep de-allocating extents until the remote-value region is gone. | ||
2182 | */ | ||
2183 | lblkno = args->rmtblkno; | ||
2184 | blkcnt = args->rmtblkcnt; | ||
2185 | done = 0; | ||
2186 | while (!done) { | ||
2187 | xfs_bmap_init(args->flist, args->firstblock); | ||
2188 | error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, | ||
2189 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, | ||
2190 | 1, args->firstblock, args->flist, | ||
2191 | &done); | ||
2192 | if (!error) { | ||
2193 | error = xfs_bmap_finish(&args->trans, args->flist, | ||
2194 | &committed); | ||
2195 | } | ||
2196 | if (error) { | ||
2197 | ASSERT(committed); | ||
2198 | args->trans = NULL; | ||
2199 | xfs_bmap_cancel(args->flist); | ||
2200 | return(error); | ||
2201 | } | ||
2202 | |||
2203 | /* | ||
2204 | * bmap_finish() may have committed the last trans and started | ||
2205 | * a new one. We need the inode to be in all transactions. | ||
2206 | */ | ||
2207 | if (committed) | ||
2208 | xfs_trans_ijoin(args->trans, args->dp, 0); | ||
2209 | |||
2210 | /* | ||
2211 | * Close out trans and start the next one in the chain. | ||
2212 | */ | ||
2213 | error = xfs_trans_roll(&args->trans, args->dp); | ||
2214 | if (error) | ||
2215 | return (error); | ||
2216 | } | ||
2217 | return(0); | ||
2218 | } | ||
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index e920d68ef509..de8dd58da46c 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h | |||
@@ -140,7 +140,6 @@ typedef struct xfs_attr_list_context { | |||
140 | * Overall external interface routines. | 140 | * Overall external interface routines. |
141 | */ | 141 | */ |
142 | int xfs_attr_inactive(struct xfs_inode *dp); | 142 | int xfs_attr_inactive(struct xfs_inode *dp); |
143 | int xfs_attr_rmtval_get(struct xfs_da_args *args); | ||
144 | int xfs_attr_list_int(struct xfs_attr_list_context *); | 143 | int xfs_attr_list_int(struct xfs_attr_list_context *); |
145 | 144 | ||
146 | #endif /* __XFS_ATTR_H__ */ | 145 | #endif /* __XFS_ATTR_H__ */ |
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index 7f8b6c8a483f..287c8089b705 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "xfs_alloc.h" | 32 | #include "xfs_alloc.h" |
33 | #include "xfs_btree.h" | 33 | #include "xfs_btree.h" |
34 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
35 | #include "xfs_attr_remote.h" | ||
35 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
36 | #include "xfs_inode.h" | 37 | #include "xfs_inode.h" |
37 | #include "xfs_inode_item.h" | 38 | #include "xfs_inode_item.h" |
diff --git a/fs/xfs/xfs_attr_remote.c b/fs/xfs/xfs_attr_remote.c new file mode 100644 index 000000000000..d0d67e935262 --- /dev/null +++ b/fs/xfs/xfs_attr_remote.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it would be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write the Free Software Foundation, | ||
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | #include "xfs.h" | ||
19 | #include "xfs_fs.h" | ||
20 | #include "xfs_types.h" | ||
21 | #include "xfs_bit.h" | ||
22 | #include "xfs_log.h" | ||
23 | #include "xfs_trans.h" | ||
24 | #include "xfs_sb.h" | ||
25 | #include "xfs_ag.h" | ||
26 | #include "xfs_mount.h" | ||
27 | #include "xfs_error.h" | ||
28 | #include "xfs_da_btree.h" | ||
29 | #include "xfs_bmap_btree.h" | ||
30 | #include "xfs_dinode.h" | ||
31 | #include "xfs_inode.h" | ||
32 | #include "xfs_alloc.h" | ||
33 | #include "xfs_inode_item.h" | ||
34 | #include "xfs_bmap.h" | ||
35 | #include "xfs_attr.h" | ||
36 | #include "xfs_attr_leaf.h" | ||
37 | #include "xfs_attr_remote.h" | ||
38 | #include "xfs_trans_space.h" | ||
39 | #include "xfs_trace.h" | ||
40 | |||
41 | |||
42 | #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ | ||
43 | |||
44 | /* | ||
45 | * Read the value associated with an attribute from the out-of-line buffer | ||
46 | * that we stored it in. | ||
47 | */ | ||
48 | int | ||
49 | xfs_attr_rmtval_get(xfs_da_args_t *args) | ||
50 | { | ||
51 | xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; | ||
52 | xfs_mount_t *mp; | ||
53 | xfs_daddr_t dblkno; | ||
54 | void *dst; | ||
55 | xfs_buf_t *bp; | ||
56 | int nmap, error, tmp, valuelen, blkcnt, i; | ||
57 | xfs_dablk_t lblkno; | ||
58 | |||
59 | trace_xfs_attr_rmtval_get(args); | ||
60 | |||
61 | ASSERT(!(args->flags & ATTR_KERNOVAL)); | ||
62 | |||
63 | mp = args->dp->i_mount; | ||
64 | dst = args->value; | ||
65 | valuelen = args->valuelen; | ||
66 | lblkno = args->rmtblkno; | ||
67 | while (valuelen > 0) { | ||
68 | nmap = ATTR_RMTVALUE_MAPSIZE; | ||
69 | error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, | ||
70 | args->rmtblkcnt, map, &nmap, | ||
71 | XFS_BMAPI_ATTRFORK); | ||
72 | if (error) | ||
73 | return(error); | ||
74 | ASSERT(nmap >= 1); | ||
75 | |||
76 | for (i = 0; (i < nmap) && (valuelen > 0); i++) { | ||
77 | ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && | ||
78 | (map[i].br_startblock != HOLESTARTBLOCK)); | ||
79 | dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); | ||
80 | blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); | ||
81 | error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, | ||
82 | dblkno, blkcnt, 0, &bp, NULL); | ||
83 | if (error) | ||
84 | return(error); | ||
85 | |||
86 | tmp = min_t(int, valuelen, BBTOB(bp->b_length)); | ||
87 | xfs_buf_iomove(bp, 0, tmp, dst, XBRW_READ); | ||
88 | xfs_buf_relse(bp); | ||
89 | dst += tmp; | ||
90 | valuelen -= tmp; | ||
91 | |||
92 | lblkno += map[i].br_blockcount; | ||
93 | } | ||
94 | } | ||
95 | ASSERT(valuelen == 0); | ||
96 | return(0); | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Write the value associated with an attribute into the out-of-line buffer | ||
101 | * that we have defined for it. | ||
102 | */ | ||
103 | int | ||
104 | xfs_attr_rmtval_set(xfs_da_args_t *args) | ||
105 | { | ||
106 | xfs_mount_t *mp; | ||
107 | xfs_fileoff_t lfileoff; | ||
108 | xfs_inode_t *dp; | ||
109 | xfs_bmbt_irec_t map; | ||
110 | xfs_daddr_t dblkno; | ||
111 | void *src; | ||
112 | xfs_buf_t *bp; | ||
113 | xfs_dablk_t lblkno; | ||
114 | int blkcnt, valuelen, nmap, error, tmp, committed; | ||
115 | |||
116 | trace_xfs_attr_rmtval_set(args); | ||
117 | |||
118 | dp = args->dp; | ||
119 | mp = dp->i_mount; | ||
120 | src = args->value; | ||
121 | |||
122 | /* | ||
123 | * Find a "hole" in the attribute address space large enough for | ||
124 | * us to drop the new attribute's value into. | ||
125 | */ | ||
126 | blkcnt = XFS_B_TO_FSB(mp, args->valuelen); | ||
127 | lfileoff = 0; | ||
128 | error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, | ||
129 | XFS_ATTR_FORK); | ||
130 | if (error) { | ||
131 | return(error); | ||
132 | } | ||
133 | args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; | ||
134 | args->rmtblkcnt = blkcnt; | ||
135 | |||
136 | /* | ||
137 | * Roll through the "value", allocating blocks on disk as required. | ||
138 | */ | ||
139 | while (blkcnt > 0) { | ||
140 | /* | ||
141 | * Allocate a single extent, up to the size of the value. | ||
142 | */ | ||
143 | xfs_bmap_init(args->flist, args->firstblock); | ||
144 | nmap = 1; | ||
145 | error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno, | ||
146 | blkcnt, | ||
147 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, | ||
148 | args->firstblock, args->total, &map, &nmap, | ||
149 | args->flist); | ||
150 | if (!error) { | ||
151 | error = xfs_bmap_finish(&args->trans, args->flist, | ||
152 | &committed); | ||
153 | } | ||
154 | if (error) { | ||
155 | ASSERT(committed); | ||
156 | args->trans = NULL; | ||
157 | xfs_bmap_cancel(args->flist); | ||
158 | return(error); | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * bmap_finish() may have committed the last trans and started | ||
163 | * a new one. We need the inode to be in all transactions. | ||
164 | */ | ||
165 | if (committed) | ||
166 | xfs_trans_ijoin(args->trans, dp, 0); | ||
167 | |||
168 | ASSERT(nmap == 1); | ||
169 | ASSERT((map.br_startblock != DELAYSTARTBLOCK) && | ||
170 | (map.br_startblock != HOLESTARTBLOCK)); | ||
171 | lblkno += map.br_blockcount; | ||
172 | blkcnt -= map.br_blockcount; | ||
173 | |||
174 | /* | ||
175 | * Start the next trans in the chain. | ||
176 | */ | ||
177 | error = xfs_trans_roll(&args->trans, dp); | ||
178 | if (error) | ||
179 | return (error); | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Roll through the "value", copying the attribute value to the | ||
184 | * already-allocated blocks. Blocks are written synchronously | ||
185 | * so that we can know they are all on disk before we turn off | ||
186 | * the INCOMPLETE flag. | ||
187 | */ | ||
188 | lblkno = args->rmtblkno; | ||
189 | valuelen = args->valuelen; | ||
190 | while (valuelen > 0) { | ||
191 | int buflen; | ||
192 | |||
193 | /* | ||
194 | * Try to remember where we decided to put the value. | ||
195 | */ | ||
196 | xfs_bmap_init(args->flist, args->firstblock); | ||
197 | nmap = 1; | ||
198 | error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, | ||
199 | args->rmtblkcnt, &map, &nmap, | ||
200 | XFS_BMAPI_ATTRFORK); | ||
201 | if (error) | ||
202 | return(error); | ||
203 | ASSERT(nmap == 1); | ||
204 | ASSERT((map.br_startblock != DELAYSTARTBLOCK) && | ||
205 | (map.br_startblock != HOLESTARTBLOCK)); | ||
206 | |||
207 | dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), | ||
208 | blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); | ||
209 | |||
210 | bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt, 0); | ||
211 | if (!bp) | ||
212 | return ENOMEM; | ||
213 | |||
214 | buflen = BBTOB(bp->b_length); | ||
215 | tmp = min_t(int, valuelen, buflen); | ||
216 | xfs_buf_iomove(bp, 0, tmp, src, XBRW_WRITE); | ||
217 | if (tmp < buflen) | ||
218 | xfs_buf_zero(bp, tmp, buflen - tmp); | ||
219 | |||
220 | error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ | ||
221 | xfs_buf_relse(bp); | ||
222 | if (error) | ||
223 | return error; | ||
224 | src += tmp; | ||
225 | valuelen -= tmp; | ||
226 | |||
227 | lblkno += map.br_blockcount; | ||
228 | } | ||
229 | ASSERT(valuelen == 0); | ||
230 | return(0); | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Remove the value associated with an attribute by deleting the | ||
235 | * out-of-line buffer that it is stored on. | ||
236 | */ | ||
237 | int | ||
238 | xfs_attr_rmtval_remove(xfs_da_args_t *args) | ||
239 | { | ||
240 | xfs_mount_t *mp; | ||
241 | xfs_bmbt_irec_t map; | ||
242 | xfs_buf_t *bp; | ||
243 | xfs_daddr_t dblkno; | ||
244 | xfs_dablk_t lblkno; | ||
245 | int valuelen, blkcnt, nmap, error, done, committed; | ||
246 | |||
247 | trace_xfs_attr_rmtval_remove(args); | ||
248 | |||
249 | mp = args->dp->i_mount; | ||
250 | |||
251 | /* | ||
252 | * Roll through the "value", invalidating the attribute value's | ||
253 | * blocks. | ||
254 | */ | ||
255 | lblkno = args->rmtblkno; | ||
256 | valuelen = args->rmtblkcnt; | ||
257 | while (valuelen > 0) { | ||
258 | /* | ||
259 | * Try to remember where we decided to put the value. | ||
260 | */ | ||
261 | nmap = 1; | ||
262 | error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, | ||
263 | args->rmtblkcnt, &map, &nmap, | ||
264 | XFS_BMAPI_ATTRFORK); | ||
265 | if (error) | ||
266 | return(error); | ||
267 | ASSERT(nmap == 1); | ||
268 | ASSERT((map.br_startblock != DELAYSTARTBLOCK) && | ||
269 | (map.br_startblock != HOLESTARTBLOCK)); | ||
270 | |||
271 | dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), | ||
272 | blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); | ||
273 | |||
274 | /* | ||
275 | * If the "remote" value is in the cache, remove it. | ||
276 | */ | ||
277 | bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, XBF_TRYLOCK); | ||
278 | if (bp) { | ||
279 | xfs_buf_stale(bp); | ||
280 | xfs_buf_relse(bp); | ||
281 | bp = NULL; | ||
282 | } | ||
283 | |||
284 | valuelen -= map.br_blockcount; | ||
285 | |||
286 | lblkno += map.br_blockcount; | ||
287 | } | ||
288 | |||
289 | /* | ||
290 | * Keep de-allocating extents until the remote-value region is gone. | ||
291 | */ | ||
292 | lblkno = args->rmtblkno; | ||
293 | blkcnt = args->rmtblkcnt; | ||
294 | done = 0; | ||
295 | while (!done) { | ||
296 | xfs_bmap_init(args->flist, args->firstblock); | ||
297 | error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, | ||
298 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, | ||
299 | 1, args->firstblock, args->flist, | ||
300 | &done); | ||
301 | if (!error) { | ||
302 | error = xfs_bmap_finish(&args->trans, args->flist, | ||
303 | &committed); | ||
304 | } | ||
305 | if (error) { | ||
306 | ASSERT(committed); | ||
307 | args->trans = NULL; | ||
308 | xfs_bmap_cancel(args->flist); | ||
309 | return(error); | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * bmap_finish() may have committed the last trans and started | ||
314 | * a new one. We need the inode to be in all transactions. | ||
315 | */ | ||
316 | if (committed) | ||
317 | xfs_trans_ijoin(args->trans, args->dp, 0); | ||
318 | |||
319 | /* | ||
320 | * Close out trans and start the next one in the chain. | ||
321 | */ | ||
322 | error = xfs_trans_roll(&args->trans, args->dp); | ||
323 | if (error) | ||
324 | return (error); | ||
325 | } | ||
326 | return(0); | ||
327 | } | ||
328 | |||
diff --git a/fs/xfs/xfs_attr_remote.h b/fs/xfs/xfs_attr_remote.h new file mode 100644 index 000000000000..2a34b9a0813e --- /dev/null +++ b/fs/xfs/xfs_attr_remote.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Red Hat, Inc. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it would be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write the Free Software Foundation, | ||
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | #ifndef __XFS_ATTR_REMOTE_H__ | ||
19 | #define __XFS_ATTR_REMOTE_H__ | ||
20 | |||
21 | int xfs_attr_rmtval_get(struct xfs_da_args *args); | ||
22 | int xfs_attr_rmtval_set(struct xfs_da_args *args); | ||
23 | int xfs_attr_rmtval_remove(struct xfs_da_args *args); | ||
24 | |||
25 | #endif /* __XFS_ATTR_REMOTE_H__ */ | ||