1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4*4882a593Smuzhiyun * Copyright (c) 2013 Red Hat, Inc.
5*4882a593Smuzhiyun * All Rights Reserved.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include "xfs.h"
8*4882a593Smuzhiyun #include "xfs_fs.h"
9*4882a593Smuzhiyun #include "xfs_shared.h"
10*4882a593Smuzhiyun #include "xfs_format.h"
11*4882a593Smuzhiyun #include "xfs_log_format.h"
12*4882a593Smuzhiyun #include "xfs_trans_resv.h"
13*4882a593Smuzhiyun #include "xfs_bit.h"
14*4882a593Smuzhiyun #include "xfs_mount.h"
15*4882a593Smuzhiyun #include "xfs_defer.h"
16*4882a593Smuzhiyun #include "xfs_da_format.h"
17*4882a593Smuzhiyun #include "xfs_da_btree.h"
18*4882a593Smuzhiyun #include "xfs_inode.h"
19*4882a593Smuzhiyun #include "xfs_trans.h"
20*4882a593Smuzhiyun #include "xfs_bmap.h"
21*4882a593Smuzhiyun #include "xfs_attr.h"
22*4882a593Smuzhiyun #include "xfs_attr_remote.h"
23*4882a593Smuzhiyun #include "xfs_trace.h"
24*4882a593Smuzhiyun #include "xfs_error.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun * Remote Attribute Values
30*4882a593Smuzhiyun * =======================
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * Remote extended attribute values are conceptually simple -- they're written
33*4882a593Smuzhiyun * to data blocks mapped by an inode's attribute fork, and they have an upper
34*4882a593Smuzhiyun * size limit of 64k. Setting a value does not involve the XFS log.
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * However, on a v5 filesystem, maximally sized remote attr values require one
37*4882a593Smuzhiyun * block more than 64k worth of space to hold both the remote attribute value
38*4882a593Smuzhiyun * header (64 bytes). On a 4k block filesystem this results in a 68k buffer;
39*4882a593Smuzhiyun * on a 64k block filesystem, this would be a 128k buffer. Note that the log
40*4882a593Smuzhiyun * format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k).
41*4882a593Smuzhiyun * Therefore, we /must/ ensure that remote attribute value buffers never touch
42*4882a593Smuzhiyun * the logging system and therefore never have a log item.
43*4882a593Smuzhiyun */
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /*
46*4882a593Smuzhiyun * Each contiguous block has a header, so it is not just a simple attribute
47*4882a593Smuzhiyun * length to FSB conversion.
48*4882a593Smuzhiyun */
49*4882a593Smuzhiyun int
xfs_attr3_rmt_blocks(struct xfs_mount * mp,int attrlen)50*4882a593Smuzhiyun xfs_attr3_rmt_blocks(
51*4882a593Smuzhiyun struct xfs_mount *mp,
52*4882a593Smuzhiyun int attrlen)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun if (xfs_sb_version_hascrc(&mp->m_sb)) {
55*4882a593Smuzhiyun int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
56*4882a593Smuzhiyun return (attrlen + buflen - 1) / buflen;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun return XFS_B_TO_FSB(mp, attrlen);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun * Checking of the remote attribute header is split into two parts. The verifier
63*4882a593Smuzhiyun * does CRC, location and bounds checking, the unpacking function checks the
64*4882a593Smuzhiyun * attribute parameters and owner.
65*4882a593Smuzhiyun */
66*4882a593Smuzhiyun static xfs_failaddr_t
xfs_attr3_rmt_hdr_ok(void * ptr,xfs_ino_t ino,uint32_t offset,uint32_t size,xfs_daddr_t bno)67*4882a593Smuzhiyun xfs_attr3_rmt_hdr_ok(
68*4882a593Smuzhiyun void *ptr,
69*4882a593Smuzhiyun xfs_ino_t ino,
70*4882a593Smuzhiyun uint32_t offset,
71*4882a593Smuzhiyun uint32_t size,
72*4882a593Smuzhiyun xfs_daddr_t bno)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun struct xfs_attr3_rmt_hdr *rmt = ptr;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun if (bno != be64_to_cpu(rmt->rm_blkno))
77*4882a593Smuzhiyun return __this_address;
78*4882a593Smuzhiyun if (offset != be32_to_cpu(rmt->rm_offset))
79*4882a593Smuzhiyun return __this_address;
80*4882a593Smuzhiyun if (size != be32_to_cpu(rmt->rm_bytes))
81*4882a593Smuzhiyun return __this_address;
82*4882a593Smuzhiyun if (ino != be64_to_cpu(rmt->rm_owner))
83*4882a593Smuzhiyun return __this_address;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* ok */
86*4882a593Smuzhiyun return NULL;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun static xfs_failaddr_t
xfs_attr3_rmt_verify(struct xfs_mount * mp,struct xfs_buf * bp,void * ptr,int fsbsize,xfs_daddr_t bno)90*4882a593Smuzhiyun xfs_attr3_rmt_verify(
91*4882a593Smuzhiyun struct xfs_mount *mp,
92*4882a593Smuzhiyun struct xfs_buf *bp,
93*4882a593Smuzhiyun void *ptr,
94*4882a593Smuzhiyun int fsbsize,
95*4882a593Smuzhiyun xfs_daddr_t bno)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun struct xfs_attr3_rmt_hdr *rmt = ptr;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (!xfs_verify_magic(bp, rmt->rm_magic))
100*4882a593Smuzhiyun return __this_address;
101*4882a593Smuzhiyun if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
102*4882a593Smuzhiyun return __this_address;
103*4882a593Smuzhiyun if (be64_to_cpu(rmt->rm_blkno) != bno)
104*4882a593Smuzhiyun return __this_address;
105*4882a593Smuzhiyun if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
106*4882a593Smuzhiyun return __this_address;
107*4882a593Smuzhiyun if (be32_to_cpu(rmt->rm_offset) +
108*4882a593Smuzhiyun be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
109*4882a593Smuzhiyun return __this_address;
110*4882a593Smuzhiyun if (rmt->rm_owner == 0)
111*4882a593Smuzhiyun return __this_address;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun return NULL;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun static int
__xfs_attr3_rmt_read_verify(struct xfs_buf * bp,bool check_crc,xfs_failaddr_t * failaddr)117*4882a593Smuzhiyun __xfs_attr3_rmt_read_verify(
118*4882a593Smuzhiyun struct xfs_buf *bp,
119*4882a593Smuzhiyun bool check_crc,
120*4882a593Smuzhiyun xfs_failaddr_t *failaddr)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun struct xfs_mount *mp = bp->b_mount;
123*4882a593Smuzhiyun char *ptr;
124*4882a593Smuzhiyun int len;
125*4882a593Smuzhiyun xfs_daddr_t bno;
126*4882a593Smuzhiyun int blksize = mp->m_attr_geo->blksize;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* no verification of non-crc buffers */
129*4882a593Smuzhiyun if (!xfs_sb_version_hascrc(&mp->m_sb))
130*4882a593Smuzhiyun return 0;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun ptr = bp->b_addr;
133*4882a593Smuzhiyun bno = bp->b_bn;
134*4882a593Smuzhiyun len = BBTOB(bp->b_length);
135*4882a593Smuzhiyun ASSERT(len >= blksize);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun while (len > 0) {
138*4882a593Smuzhiyun if (check_crc &&
139*4882a593Smuzhiyun !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
140*4882a593Smuzhiyun *failaddr = __this_address;
141*4882a593Smuzhiyun return -EFSBADCRC;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
144*4882a593Smuzhiyun if (*failaddr)
145*4882a593Smuzhiyun return -EFSCORRUPTED;
146*4882a593Smuzhiyun len -= blksize;
147*4882a593Smuzhiyun ptr += blksize;
148*4882a593Smuzhiyun bno += BTOBB(blksize);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun if (len != 0) {
152*4882a593Smuzhiyun *failaddr = __this_address;
153*4882a593Smuzhiyun return -EFSCORRUPTED;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun return 0;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun static void
xfs_attr3_rmt_read_verify(struct xfs_buf * bp)160*4882a593Smuzhiyun xfs_attr3_rmt_read_verify(
161*4882a593Smuzhiyun struct xfs_buf *bp)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun xfs_failaddr_t fa;
164*4882a593Smuzhiyun int error;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun error = __xfs_attr3_rmt_read_verify(bp, true, &fa);
167*4882a593Smuzhiyun if (error)
168*4882a593Smuzhiyun xfs_verifier_error(bp, error, fa);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun static xfs_failaddr_t
xfs_attr3_rmt_verify_struct(struct xfs_buf * bp)172*4882a593Smuzhiyun xfs_attr3_rmt_verify_struct(
173*4882a593Smuzhiyun struct xfs_buf *bp)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun xfs_failaddr_t fa;
176*4882a593Smuzhiyun int error;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun error = __xfs_attr3_rmt_read_verify(bp, false, &fa);
179*4882a593Smuzhiyun return error ? fa : NULL;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun static void
xfs_attr3_rmt_write_verify(struct xfs_buf * bp)183*4882a593Smuzhiyun xfs_attr3_rmt_write_verify(
184*4882a593Smuzhiyun struct xfs_buf *bp)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun struct xfs_mount *mp = bp->b_mount;
187*4882a593Smuzhiyun xfs_failaddr_t fa;
188*4882a593Smuzhiyun int blksize = mp->m_attr_geo->blksize;
189*4882a593Smuzhiyun char *ptr;
190*4882a593Smuzhiyun int len;
191*4882a593Smuzhiyun xfs_daddr_t bno;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* no verification of non-crc buffers */
194*4882a593Smuzhiyun if (!xfs_sb_version_hascrc(&mp->m_sb))
195*4882a593Smuzhiyun return;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun ptr = bp->b_addr;
198*4882a593Smuzhiyun bno = bp->b_bn;
199*4882a593Smuzhiyun len = BBTOB(bp->b_length);
200*4882a593Smuzhiyun ASSERT(len >= blksize);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun while (len > 0) {
203*4882a593Smuzhiyun struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
206*4882a593Smuzhiyun if (fa) {
207*4882a593Smuzhiyun xfs_verifier_error(bp, -EFSCORRUPTED, fa);
208*4882a593Smuzhiyun return;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /*
212*4882a593Smuzhiyun * Ensure we aren't writing bogus LSNs to disk. See
213*4882a593Smuzhiyun * xfs_attr3_rmt_hdr_set() for the explanation.
214*4882a593Smuzhiyun */
215*4882a593Smuzhiyun if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
216*4882a593Smuzhiyun xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
217*4882a593Smuzhiyun return;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun len -= blksize;
222*4882a593Smuzhiyun ptr += blksize;
223*4882a593Smuzhiyun bno += BTOBB(blksize);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun if (len != 0)
227*4882a593Smuzhiyun xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
231*4882a593Smuzhiyun .name = "xfs_attr3_rmt",
232*4882a593Smuzhiyun .magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) },
233*4882a593Smuzhiyun .verify_read = xfs_attr3_rmt_read_verify,
234*4882a593Smuzhiyun .verify_write = xfs_attr3_rmt_write_verify,
235*4882a593Smuzhiyun .verify_struct = xfs_attr3_rmt_verify_struct,
236*4882a593Smuzhiyun };
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun STATIC int
xfs_attr3_rmt_hdr_set(struct xfs_mount * mp,void * ptr,xfs_ino_t ino,uint32_t offset,uint32_t size,xfs_daddr_t bno)239*4882a593Smuzhiyun xfs_attr3_rmt_hdr_set(
240*4882a593Smuzhiyun struct xfs_mount *mp,
241*4882a593Smuzhiyun void *ptr,
242*4882a593Smuzhiyun xfs_ino_t ino,
243*4882a593Smuzhiyun uint32_t offset,
244*4882a593Smuzhiyun uint32_t size,
245*4882a593Smuzhiyun xfs_daddr_t bno)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun struct xfs_attr3_rmt_hdr *rmt = ptr;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun if (!xfs_sb_version_hascrc(&mp->m_sb))
250*4882a593Smuzhiyun return 0;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
253*4882a593Smuzhiyun rmt->rm_offset = cpu_to_be32(offset);
254*4882a593Smuzhiyun rmt->rm_bytes = cpu_to_be32(size);
255*4882a593Smuzhiyun uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
256*4882a593Smuzhiyun rmt->rm_owner = cpu_to_be64(ino);
257*4882a593Smuzhiyun rmt->rm_blkno = cpu_to_be64(bno);
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun /*
260*4882a593Smuzhiyun * Remote attribute blocks are written synchronously, so we don't
261*4882a593Smuzhiyun * have an LSN that we can stamp in them that makes any sense to log
262*4882a593Smuzhiyun * recovery. To ensure that log recovery handles overwrites of these
263*4882a593Smuzhiyun * blocks sanely (i.e. once they've been freed and reallocated as some
264*4882a593Smuzhiyun * other type of metadata) we need to ensure that the LSN has a value
265*4882a593Smuzhiyun * that tells log recovery to ignore the LSN and overwrite the buffer
266*4882a593Smuzhiyun * with whatever is in it's log. To do this, we use the magic
267*4882a593Smuzhiyun * NULLCOMMITLSN to indicate that the LSN is invalid.
268*4882a593Smuzhiyun */
269*4882a593Smuzhiyun rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun return sizeof(struct xfs_attr3_rmt_hdr);
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /*
275*4882a593Smuzhiyun * Helper functions to copy attribute data in and out of the one disk extents
276*4882a593Smuzhiyun */
277*4882a593Smuzhiyun STATIC int
xfs_attr_rmtval_copyout(struct xfs_mount * mp,struct xfs_buf * bp,xfs_ino_t ino,int * offset,int * valuelen,uint8_t ** dst)278*4882a593Smuzhiyun xfs_attr_rmtval_copyout(
279*4882a593Smuzhiyun struct xfs_mount *mp,
280*4882a593Smuzhiyun struct xfs_buf *bp,
281*4882a593Smuzhiyun xfs_ino_t ino,
282*4882a593Smuzhiyun int *offset,
283*4882a593Smuzhiyun int *valuelen,
284*4882a593Smuzhiyun uint8_t **dst)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun char *src = bp->b_addr;
287*4882a593Smuzhiyun xfs_daddr_t bno = bp->b_bn;
288*4882a593Smuzhiyun int len = BBTOB(bp->b_length);
289*4882a593Smuzhiyun int blksize = mp->m_attr_geo->blksize;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun ASSERT(len >= blksize);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun while (len > 0 && *valuelen > 0) {
294*4882a593Smuzhiyun int hdr_size = 0;
295*4882a593Smuzhiyun int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun byte_cnt = min(*valuelen, byte_cnt);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if (xfs_sb_version_hascrc(&mp->m_sb)) {
300*4882a593Smuzhiyun if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
301*4882a593Smuzhiyun byte_cnt, bno)) {
302*4882a593Smuzhiyun xfs_alert(mp,
303*4882a593Smuzhiyun "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
304*4882a593Smuzhiyun bno, *offset, byte_cnt, ino);
305*4882a593Smuzhiyun return -EFSCORRUPTED;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun memcpy(*dst, src + hdr_size, byte_cnt);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun /* roll buffer forwards */
313*4882a593Smuzhiyun len -= blksize;
314*4882a593Smuzhiyun src += blksize;
315*4882a593Smuzhiyun bno += BTOBB(blksize);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /* roll attribute data forwards */
318*4882a593Smuzhiyun *valuelen -= byte_cnt;
319*4882a593Smuzhiyun *dst += byte_cnt;
320*4882a593Smuzhiyun *offset += byte_cnt;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun return 0;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun STATIC void
xfs_attr_rmtval_copyin(struct xfs_mount * mp,struct xfs_buf * bp,xfs_ino_t ino,int * offset,int * valuelen,uint8_t ** src)326*4882a593Smuzhiyun xfs_attr_rmtval_copyin(
327*4882a593Smuzhiyun struct xfs_mount *mp,
328*4882a593Smuzhiyun struct xfs_buf *bp,
329*4882a593Smuzhiyun xfs_ino_t ino,
330*4882a593Smuzhiyun int *offset,
331*4882a593Smuzhiyun int *valuelen,
332*4882a593Smuzhiyun uint8_t **src)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun char *dst = bp->b_addr;
335*4882a593Smuzhiyun xfs_daddr_t bno = bp->b_bn;
336*4882a593Smuzhiyun int len = BBTOB(bp->b_length);
337*4882a593Smuzhiyun int blksize = mp->m_attr_geo->blksize;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun ASSERT(len >= blksize);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun while (len > 0 && *valuelen > 0) {
342*4882a593Smuzhiyun int hdr_size;
343*4882a593Smuzhiyun int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun byte_cnt = min(*valuelen, byte_cnt);
346*4882a593Smuzhiyun hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
347*4882a593Smuzhiyun byte_cnt, bno);
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun memcpy(dst + hdr_size, *src, byte_cnt);
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun /*
352*4882a593Smuzhiyun * If this is the last block, zero the remainder of it.
353*4882a593Smuzhiyun * Check that we are actually the last block, too.
354*4882a593Smuzhiyun */
355*4882a593Smuzhiyun if (byte_cnt + hdr_size < blksize) {
356*4882a593Smuzhiyun ASSERT(*valuelen - byte_cnt == 0);
357*4882a593Smuzhiyun ASSERT(len == blksize);
358*4882a593Smuzhiyun memset(dst + hdr_size + byte_cnt, 0,
359*4882a593Smuzhiyun blksize - hdr_size - byte_cnt);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun /* roll buffer forwards */
363*4882a593Smuzhiyun len -= blksize;
364*4882a593Smuzhiyun dst += blksize;
365*4882a593Smuzhiyun bno += BTOBB(blksize);
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun /* roll attribute data forwards */
368*4882a593Smuzhiyun *valuelen -= byte_cnt;
369*4882a593Smuzhiyun *src += byte_cnt;
370*4882a593Smuzhiyun *offset += byte_cnt;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun /*
375*4882a593Smuzhiyun * Read the value associated with an attribute from the out-of-line buffer
376*4882a593Smuzhiyun * that we stored it in.
377*4882a593Smuzhiyun *
378*4882a593Smuzhiyun * Returns 0 on successful retrieval, otherwise an error.
379*4882a593Smuzhiyun */
380*4882a593Smuzhiyun int
xfs_attr_rmtval_get(struct xfs_da_args * args)381*4882a593Smuzhiyun xfs_attr_rmtval_get(
382*4882a593Smuzhiyun struct xfs_da_args *args)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE];
385*4882a593Smuzhiyun struct xfs_mount *mp = args->dp->i_mount;
386*4882a593Smuzhiyun struct xfs_buf *bp;
387*4882a593Smuzhiyun xfs_dablk_t lblkno = args->rmtblkno;
388*4882a593Smuzhiyun uint8_t *dst = args->value;
389*4882a593Smuzhiyun int valuelen;
390*4882a593Smuzhiyun int nmap;
391*4882a593Smuzhiyun int error;
392*4882a593Smuzhiyun int blkcnt = args->rmtblkcnt;
393*4882a593Smuzhiyun int i;
394*4882a593Smuzhiyun int offset = 0;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun trace_xfs_attr_rmtval_get(args);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun ASSERT(args->valuelen != 0);
399*4882a593Smuzhiyun ASSERT(args->rmtvaluelen == args->valuelen);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun valuelen = args->rmtvaluelen;
402*4882a593Smuzhiyun while (valuelen > 0) {
403*4882a593Smuzhiyun nmap = ATTR_RMTVALUE_MAPSIZE;
404*4882a593Smuzhiyun error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
405*4882a593Smuzhiyun blkcnt, map, &nmap,
406*4882a593Smuzhiyun XFS_BMAPI_ATTRFORK);
407*4882a593Smuzhiyun if (error)
408*4882a593Smuzhiyun return error;
409*4882a593Smuzhiyun ASSERT(nmap >= 1);
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun for (i = 0; (i < nmap) && (valuelen > 0); i++) {
412*4882a593Smuzhiyun xfs_daddr_t dblkno;
413*4882a593Smuzhiyun int dblkcnt;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
416*4882a593Smuzhiyun (map[i].br_startblock != HOLESTARTBLOCK));
417*4882a593Smuzhiyun dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
418*4882a593Smuzhiyun dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
419*4882a593Smuzhiyun error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
420*4882a593Smuzhiyun 0, &bp, &xfs_attr3_rmt_buf_ops);
421*4882a593Smuzhiyun if (error)
422*4882a593Smuzhiyun return error;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
425*4882a593Smuzhiyun &offset, &valuelen,
426*4882a593Smuzhiyun &dst);
427*4882a593Smuzhiyun xfs_buf_relse(bp);
428*4882a593Smuzhiyun if (error)
429*4882a593Smuzhiyun return error;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /* roll attribute extent map forwards */
432*4882a593Smuzhiyun lblkno += map[i].br_blockcount;
433*4882a593Smuzhiyun blkcnt -= map[i].br_blockcount;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun ASSERT(valuelen == 0);
437*4882a593Smuzhiyun return 0;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun /*
441*4882a593Smuzhiyun * Find a "hole" in the attribute address space large enough for us to drop the
442*4882a593Smuzhiyun * new attribute's value into
443*4882a593Smuzhiyun */
444*4882a593Smuzhiyun STATIC int
xfs_attr_rmt_find_hole(struct xfs_da_args * args)445*4882a593Smuzhiyun xfs_attr_rmt_find_hole(
446*4882a593Smuzhiyun struct xfs_da_args *args)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun struct xfs_inode *dp = args->dp;
449*4882a593Smuzhiyun struct xfs_mount *mp = dp->i_mount;
450*4882a593Smuzhiyun int error;
451*4882a593Smuzhiyun int blkcnt;
452*4882a593Smuzhiyun xfs_fileoff_t lfileoff = 0;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /*
455*4882a593Smuzhiyun * Because CRC enable attributes have headers, we can't just do a
456*4882a593Smuzhiyun * straight byte to FSB conversion and have to take the header space
457*4882a593Smuzhiyun * into account.
458*4882a593Smuzhiyun */
459*4882a593Smuzhiyun blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
460*4882a593Smuzhiyun error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
461*4882a593Smuzhiyun XFS_ATTR_FORK);
462*4882a593Smuzhiyun if (error)
463*4882a593Smuzhiyun return error;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun args->rmtblkno = (xfs_dablk_t)lfileoff;
466*4882a593Smuzhiyun args->rmtblkcnt = blkcnt;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun return 0;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun STATIC int
xfs_attr_rmtval_set_value(struct xfs_da_args * args)472*4882a593Smuzhiyun xfs_attr_rmtval_set_value(
473*4882a593Smuzhiyun struct xfs_da_args *args)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun struct xfs_inode *dp = args->dp;
476*4882a593Smuzhiyun struct xfs_mount *mp = dp->i_mount;
477*4882a593Smuzhiyun struct xfs_bmbt_irec map;
478*4882a593Smuzhiyun xfs_dablk_t lblkno;
479*4882a593Smuzhiyun uint8_t *src = args->value;
480*4882a593Smuzhiyun int blkcnt;
481*4882a593Smuzhiyun int valuelen;
482*4882a593Smuzhiyun int nmap;
483*4882a593Smuzhiyun int error;
484*4882a593Smuzhiyun int offset = 0;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun /*
487*4882a593Smuzhiyun * Roll through the "value", copying the attribute value to the
488*4882a593Smuzhiyun * already-allocated blocks. Blocks are written synchronously
489*4882a593Smuzhiyun * so that we can know they are all on disk before we turn off
490*4882a593Smuzhiyun * the INCOMPLETE flag.
491*4882a593Smuzhiyun */
492*4882a593Smuzhiyun lblkno = args->rmtblkno;
493*4882a593Smuzhiyun blkcnt = args->rmtblkcnt;
494*4882a593Smuzhiyun valuelen = args->rmtvaluelen;
495*4882a593Smuzhiyun while (valuelen > 0) {
496*4882a593Smuzhiyun struct xfs_buf *bp;
497*4882a593Smuzhiyun xfs_daddr_t dblkno;
498*4882a593Smuzhiyun int dblkcnt;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun ASSERT(blkcnt > 0);
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun nmap = 1;
503*4882a593Smuzhiyun error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
504*4882a593Smuzhiyun blkcnt, &map, &nmap,
505*4882a593Smuzhiyun XFS_BMAPI_ATTRFORK);
506*4882a593Smuzhiyun if (error)
507*4882a593Smuzhiyun return error;
508*4882a593Smuzhiyun ASSERT(nmap == 1);
509*4882a593Smuzhiyun ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
510*4882a593Smuzhiyun (map.br_startblock != HOLESTARTBLOCK));
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
513*4882a593Smuzhiyun dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
516*4882a593Smuzhiyun if (error)
517*4882a593Smuzhiyun return error;
518*4882a593Smuzhiyun bp->b_ops = &xfs_attr3_rmt_buf_ops;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
521*4882a593Smuzhiyun &valuelen, &src);
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
524*4882a593Smuzhiyun xfs_buf_relse(bp);
525*4882a593Smuzhiyun if (error)
526*4882a593Smuzhiyun return error;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /* roll attribute extent map forwards */
530*4882a593Smuzhiyun lblkno += map.br_blockcount;
531*4882a593Smuzhiyun blkcnt -= map.br_blockcount;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun ASSERT(valuelen == 0);
534*4882a593Smuzhiyun return 0;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun /* Mark stale any incore buffers for the remote value. */
538*4882a593Smuzhiyun int
xfs_attr_rmtval_stale(struct xfs_inode * ip,struct xfs_bmbt_irec * map,xfs_buf_flags_t incore_flags)539*4882a593Smuzhiyun xfs_attr_rmtval_stale(
540*4882a593Smuzhiyun struct xfs_inode *ip,
541*4882a593Smuzhiyun struct xfs_bmbt_irec *map,
542*4882a593Smuzhiyun xfs_buf_flags_t incore_flags)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun struct xfs_mount *mp = ip->i_mount;
545*4882a593Smuzhiyun struct xfs_buf *bp;
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||
550*4882a593Smuzhiyun XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK))
551*4882a593Smuzhiyun return -EFSCORRUPTED;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun bp = xfs_buf_incore(mp->m_ddev_targp,
554*4882a593Smuzhiyun XFS_FSB_TO_DADDR(mp, map->br_startblock),
555*4882a593Smuzhiyun XFS_FSB_TO_BB(mp, map->br_blockcount), incore_flags);
556*4882a593Smuzhiyun if (bp) {
557*4882a593Smuzhiyun xfs_buf_stale(bp);
558*4882a593Smuzhiyun xfs_buf_relse(bp);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun return 0;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun /*
565*4882a593Smuzhiyun * Write the value associated with an attribute into the out-of-line buffer
566*4882a593Smuzhiyun * that we have defined for it.
567*4882a593Smuzhiyun */
568*4882a593Smuzhiyun int
xfs_attr_rmtval_set(struct xfs_da_args * args)569*4882a593Smuzhiyun xfs_attr_rmtval_set(
570*4882a593Smuzhiyun struct xfs_da_args *args)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun struct xfs_inode *dp = args->dp;
573*4882a593Smuzhiyun struct xfs_bmbt_irec map;
574*4882a593Smuzhiyun xfs_dablk_t lblkno;
575*4882a593Smuzhiyun int blkcnt;
576*4882a593Smuzhiyun int nmap;
577*4882a593Smuzhiyun int error;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun trace_xfs_attr_rmtval_set(args);
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun error = xfs_attr_rmt_find_hole(args);
582*4882a593Smuzhiyun if (error)
583*4882a593Smuzhiyun return error;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun blkcnt = args->rmtblkcnt;
586*4882a593Smuzhiyun lblkno = (xfs_dablk_t)args->rmtblkno;
587*4882a593Smuzhiyun /*
588*4882a593Smuzhiyun * Roll through the "value", allocating blocks on disk as required.
589*4882a593Smuzhiyun */
590*4882a593Smuzhiyun while (blkcnt > 0) {
591*4882a593Smuzhiyun /*
592*4882a593Smuzhiyun * Allocate a single extent, up to the size of the value.
593*4882a593Smuzhiyun *
594*4882a593Smuzhiyun * Note that we have to consider this a data allocation as we
595*4882a593Smuzhiyun * write the remote attribute without logging the contents.
596*4882a593Smuzhiyun * Hence we must ensure that we aren't using blocks that are on
597*4882a593Smuzhiyun * the busy list so that we don't overwrite blocks which have
598*4882a593Smuzhiyun * recently been freed but their transactions are not yet
599*4882a593Smuzhiyun * committed to disk. If we overwrite the contents of a busy
600*4882a593Smuzhiyun * extent and then crash then the block may not contain the
601*4882a593Smuzhiyun * correct metadata after log recovery occurs.
602*4882a593Smuzhiyun */
603*4882a593Smuzhiyun nmap = 1;
604*4882a593Smuzhiyun error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
605*4882a593Smuzhiyun blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
606*4882a593Smuzhiyun &nmap);
607*4882a593Smuzhiyun if (error)
608*4882a593Smuzhiyun return error;
609*4882a593Smuzhiyun error = xfs_defer_finish(&args->trans);
610*4882a593Smuzhiyun if (error)
611*4882a593Smuzhiyun return error;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun ASSERT(nmap == 1);
614*4882a593Smuzhiyun ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
615*4882a593Smuzhiyun (map.br_startblock != HOLESTARTBLOCK));
616*4882a593Smuzhiyun lblkno += map.br_blockcount;
617*4882a593Smuzhiyun blkcnt -= map.br_blockcount;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun /*
620*4882a593Smuzhiyun * Start the next trans in the chain.
621*4882a593Smuzhiyun */
622*4882a593Smuzhiyun error = xfs_trans_roll_inode(&args->trans, dp);
623*4882a593Smuzhiyun if (error)
624*4882a593Smuzhiyun return error;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun return xfs_attr_rmtval_set_value(args);
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun /*
631*4882a593Smuzhiyun * Remove the value associated with an attribute by deleting the
632*4882a593Smuzhiyun * out-of-line buffer that it is stored on.
633*4882a593Smuzhiyun */
634*4882a593Smuzhiyun int
xfs_attr_rmtval_invalidate(struct xfs_da_args * args)635*4882a593Smuzhiyun xfs_attr_rmtval_invalidate(
636*4882a593Smuzhiyun struct xfs_da_args *args)
637*4882a593Smuzhiyun {
638*4882a593Smuzhiyun xfs_dablk_t lblkno;
639*4882a593Smuzhiyun int blkcnt;
640*4882a593Smuzhiyun int error;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun /*
643*4882a593Smuzhiyun * Roll through the "value", invalidating the attribute value's blocks.
644*4882a593Smuzhiyun */
645*4882a593Smuzhiyun lblkno = args->rmtblkno;
646*4882a593Smuzhiyun blkcnt = args->rmtblkcnt;
647*4882a593Smuzhiyun while (blkcnt > 0) {
648*4882a593Smuzhiyun struct xfs_bmbt_irec map;
649*4882a593Smuzhiyun int nmap;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun /*
652*4882a593Smuzhiyun * Try to remember where we decided to put the value.
653*4882a593Smuzhiyun */
654*4882a593Smuzhiyun nmap = 1;
655*4882a593Smuzhiyun error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
656*4882a593Smuzhiyun blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
657*4882a593Smuzhiyun if (error)
658*4882a593Smuzhiyun return error;
659*4882a593Smuzhiyun if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1))
660*4882a593Smuzhiyun return -EFSCORRUPTED;
661*4882a593Smuzhiyun error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
662*4882a593Smuzhiyun if (error)
663*4882a593Smuzhiyun return error;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun lblkno += map.br_blockcount;
666*4882a593Smuzhiyun blkcnt -= map.br_blockcount;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun return 0;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun /*
672*4882a593Smuzhiyun * Remove the value associated with an attribute by deleting the
673*4882a593Smuzhiyun * out-of-line buffer that it is stored on.
674*4882a593Smuzhiyun */
675*4882a593Smuzhiyun int
xfs_attr_rmtval_remove(struct xfs_da_args * args)676*4882a593Smuzhiyun xfs_attr_rmtval_remove(
677*4882a593Smuzhiyun struct xfs_da_args *args)
678*4882a593Smuzhiyun {
679*4882a593Smuzhiyun int error;
680*4882a593Smuzhiyun int retval;
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun trace_xfs_attr_rmtval_remove(args);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun /*
685*4882a593Smuzhiyun * Keep de-allocating extents until the remote-value region is gone.
686*4882a593Smuzhiyun */
687*4882a593Smuzhiyun do {
688*4882a593Smuzhiyun retval = __xfs_attr_rmtval_remove(args);
689*4882a593Smuzhiyun if (retval && retval != -EAGAIN)
690*4882a593Smuzhiyun return retval;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun /*
693*4882a593Smuzhiyun * Close out trans and start the next one in the chain.
694*4882a593Smuzhiyun */
695*4882a593Smuzhiyun error = xfs_trans_roll_inode(&args->trans, args->dp);
696*4882a593Smuzhiyun if (error)
697*4882a593Smuzhiyun return error;
698*4882a593Smuzhiyun } while (retval == -EAGAIN);
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun return 0;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun /*
704*4882a593Smuzhiyun * Remove the value associated with an attribute by deleting the out-of-line
705*4882a593Smuzhiyun * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
706*4882a593Smuzhiyun * transaction and re-call the function
707*4882a593Smuzhiyun */
708*4882a593Smuzhiyun int
__xfs_attr_rmtval_remove(struct xfs_da_args * args)709*4882a593Smuzhiyun __xfs_attr_rmtval_remove(
710*4882a593Smuzhiyun struct xfs_da_args *args)
711*4882a593Smuzhiyun {
712*4882a593Smuzhiyun int error, done;
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun /*
715*4882a593Smuzhiyun * Unmap value blocks for this attr.
716*4882a593Smuzhiyun */
717*4882a593Smuzhiyun error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
718*4882a593Smuzhiyun args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
719*4882a593Smuzhiyun if (error)
720*4882a593Smuzhiyun return error;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun error = xfs_defer_finish(&args->trans);
723*4882a593Smuzhiyun if (error)
724*4882a593Smuzhiyun return error;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun if (!done)
727*4882a593Smuzhiyun return -EAGAIN;
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun return error;
730*4882a593Smuzhiyun }
731