aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/Makefile1
-rw-r--r--fs/xfs/xfs_attr.c298
-rw-r--r--fs/xfs/xfs_attr.h1
-rw-r--r--fs/xfs/xfs_attr_leaf.c1
-rw-r--r--fs/xfs/xfs_attr_remote.c328
-rw-r--r--fs/xfs/xfs_attr_remote.h25
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);
73STATIC int xfs_attr_fillstate(xfs_da_state_t *state); 74STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
74STATIC int xfs_attr_refillstate(xfs_da_state_t *state); 75STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
75 76
76/*
77 * Routines to manipulate out-of-line attribute values.
78 */
79STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
80STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);
81
82#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */
83 77
84STATIC int 78STATIC int
85xfs_attr_name_to_xname( 79xfs_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 */
1939int
1940xfs_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 */
1994STATIC int
1995xfs_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 */
2128STATIC int
2129xfs_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 */
142int xfs_attr_inactive(struct xfs_inode *dp); 142int xfs_attr_inactive(struct xfs_inode *dp);
143int xfs_attr_rmtval_get(struct xfs_da_args *args);
144int xfs_attr_list_int(struct xfs_attr_list_context *); 143int 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 */
48int
49xfs_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 */
103int
104xfs_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 */
237int
238xfs_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
21int xfs_attr_rmtval_get(struct xfs_da_args *args);
22int xfs_attr_rmtval_set(struct xfs_da_args *args);
23int xfs_attr_rmtval_remove(struct xfs_da_args *args);
24
25#endif /* __XFS_ATTR_REMOTE_H__ */