diff options
-rw-r--r-- | fs/xfs/xfs_attr_remote.c | 324 | ||||
-rw-r--r-- | fs/xfs/xfs_attr_remote.h | 19 |
2 files changed, 292 insertions, 51 deletions
diff --git a/fs/xfs/xfs_attr_remote.c b/fs/xfs/xfs_attr_remote.c index d0d67e935262..53da46b46c2f 100644 --- a/fs/xfs/xfs_attr_remote.c +++ b/fs/xfs/xfs_attr_remote.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. |
3 | * Copyright (c) 2013 Red Hat, Inc. | ||
3 | * All Rights Reserved. | 4 | * All Rights Reserved. |
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -37,63 +38,232 @@ | |||
37 | #include "xfs_attr_remote.h" | 38 | #include "xfs_attr_remote.h" |
38 | #include "xfs_trans_space.h" | 39 | #include "xfs_trans_space.h" |
39 | #include "xfs_trace.h" | 40 | #include "xfs_trace.h" |
40 | 41 | #include "xfs_cksum.h" | |
42 | #include "xfs_buf_item.h" | ||
41 | 43 | ||
42 | #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ | 44 | #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ |
43 | 45 | ||
44 | /* | 46 | /* |
47 | * Each contiguous block has a header, so it is not just a simple attribute | ||
48 | * length to FSB conversion. | ||
49 | */ | ||
50 | static int | ||
51 | xfs_attr3_rmt_blocks( | ||
52 | struct xfs_mount *mp, | ||
53 | int attrlen) | ||
54 | { | ||
55 | int fsblocks = 0; | ||
56 | int len = attrlen; | ||
57 | |||
58 | do { | ||
59 | fsblocks++; | ||
60 | len -= XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize); | ||
61 | } while (len > 0); | ||
62 | |||
63 | return fsblocks; | ||
64 | } | ||
65 | |||
66 | static bool | ||
67 | xfs_attr3_rmt_verify( | ||
68 | struct xfs_buf *bp) | ||
69 | { | ||
70 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
71 | struct xfs_attr3_rmt_hdr *rmt = bp->b_addr; | ||
72 | |||
73 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
74 | return false; | ||
75 | if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC)) | ||
76 | return false; | ||
77 | if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_uuid)) | ||
78 | return false; | ||
79 | if (bp->b_bn != be64_to_cpu(rmt->rm_blkno)) | ||
80 | return false; | ||
81 | if (be32_to_cpu(rmt->rm_offset) + | ||
82 | be32_to_cpu(rmt->rm_bytes) >= MAXPATHLEN) | ||
83 | return false; | ||
84 | if (rmt->rm_owner == 0) | ||
85 | return false; | ||
86 | |||
87 | return true; | ||
88 | } | ||
89 | |||
90 | static void | ||
91 | xfs_attr3_rmt_read_verify( | ||
92 | struct xfs_buf *bp) | ||
93 | { | ||
94 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
95 | |||
96 | /* no verification of non-crc buffers */ | ||
97 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
98 | return; | ||
99 | |||
100 | if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
101 | XFS_ATTR3_RMT_CRC_OFF) || | ||
102 | !xfs_attr3_rmt_verify(bp)) { | ||
103 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
104 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | xfs_attr3_rmt_write_verify( | ||
110 | struct xfs_buf *bp) | ||
111 | { | ||
112 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
113 | struct xfs_buf_log_item *bip = bp->b_fspriv; | ||
114 | |||
115 | /* no verification of non-crc buffers */ | ||
116 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
117 | return; | ||
118 | |||
119 | if (!xfs_attr3_rmt_verify(bp)) { | ||
120 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
121 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | if (bip) { | ||
126 | struct xfs_attr3_rmt_hdr *rmt = bp->b_addr; | ||
127 | rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn); | ||
128 | } | ||
129 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
130 | XFS_ATTR3_RMT_CRC_OFF); | ||
131 | } | ||
132 | |||
133 | const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = { | ||
134 | .verify_read = xfs_attr3_rmt_read_verify, | ||
135 | .verify_write = xfs_attr3_rmt_write_verify, | ||
136 | }; | ||
137 | |||
138 | static int | ||
139 | xfs_attr3_rmt_hdr_set( | ||
140 | struct xfs_mount *mp, | ||
141 | xfs_ino_t ino, | ||
142 | uint32_t offset, | ||
143 | uint32_t size, | ||
144 | struct xfs_buf *bp) | ||
145 | { | ||
146 | struct xfs_attr3_rmt_hdr *rmt = bp->b_addr; | ||
147 | |||
148 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
149 | return 0; | ||
150 | |||
151 | rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC); | ||
152 | rmt->rm_offset = cpu_to_be32(offset); | ||
153 | rmt->rm_bytes = cpu_to_be32(size); | ||
154 | uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_uuid); | ||
155 | rmt->rm_owner = cpu_to_be64(ino); | ||
156 | rmt->rm_blkno = cpu_to_be64(bp->b_bn); | ||
157 | bp->b_ops = &xfs_attr3_rmt_buf_ops; | ||
158 | |||
159 | return sizeof(struct xfs_attr3_rmt_hdr); | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * Checking of the remote attribute header is split into two parts. the verifier | ||
164 | * does CRC, location and bounds checking, the unpacking function checks the | ||
165 | * attribute parameters and owner. | ||
166 | */ | ||
167 | static bool | ||
168 | xfs_attr3_rmt_hdr_ok( | ||
169 | struct xfs_mount *mp, | ||
170 | xfs_ino_t ino, | ||
171 | uint32_t offset, | ||
172 | uint32_t size, | ||
173 | struct xfs_buf *bp) | ||
174 | { | ||
175 | struct xfs_attr3_rmt_hdr *rmt = bp->b_addr; | ||
176 | |||
177 | if (offset != be32_to_cpu(rmt->rm_offset)) | ||
178 | return false; | ||
179 | if (size != be32_to_cpu(rmt->rm_bytes)) | ||
180 | return false; | ||
181 | if (ino != be64_to_cpu(rmt->rm_owner)) | ||
182 | return false; | ||
183 | |||
184 | /* ok */ | ||
185 | return true; | ||
186 | |||
187 | } | ||
188 | |||
189 | /* | ||
45 | * Read the value associated with an attribute from the out-of-line buffer | 190 | * Read the value associated with an attribute from the out-of-line buffer |
46 | * that we stored it in. | 191 | * that we stored it in. |
47 | */ | 192 | */ |
48 | int | 193 | int |
49 | xfs_attr_rmtval_get(xfs_da_args_t *args) | 194 | xfs_attr_rmtval_get( |
195 | struct xfs_da_args *args) | ||
50 | { | 196 | { |
51 | xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; | 197 | struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE]; |
52 | xfs_mount_t *mp; | 198 | struct xfs_mount *mp = args->dp->i_mount; |
53 | xfs_daddr_t dblkno; | 199 | struct xfs_buf *bp; |
54 | void *dst; | 200 | xfs_daddr_t dblkno; |
55 | xfs_buf_t *bp; | 201 | xfs_dablk_t lblkno = args->rmtblkno; |
56 | int nmap, error, tmp, valuelen, blkcnt, i; | 202 | void *dst = args->value; |
57 | xfs_dablk_t lblkno; | 203 | int valuelen = args->valuelen; |
204 | int nmap; | ||
205 | int error; | ||
206 | int blkcnt; | ||
207 | int i; | ||
208 | int offset = 0; | ||
58 | 209 | ||
59 | trace_xfs_attr_rmtval_get(args); | 210 | trace_xfs_attr_rmtval_get(args); |
60 | 211 | ||
61 | ASSERT(!(args->flags & ATTR_KERNOVAL)); | 212 | ASSERT(!(args->flags & ATTR_KERNOVAL)); |
62 | 213 | ||
63 | mp = args->dp->i_mount; | ||
64 | dst = args->value; | ||
65 | valuelen = args->valuelen; | ||
66 | lblkno = args->rmtblkno; | ||
67 | while (valuelen > 0) { | 214 | while (valuelen > 0) { |
68 | nmap = ATTR_RMTVALUE_MAPSIZE; | 215 | nmap = ATTR_RMTVALUE_MAPSIZE; |
69 | error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, | 216 | error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, |
70 | args->rmtblkcnt, map, &nmap, | 217 | args->rmtblkcnt, map, &nmap, |
71 | XFS_BMAPI_ATTRFORK); | 218 | XFS_BMAPI_ATTRFORK); |
72 | if (error) | 219 | if (error) |
73 | return(error); | 220 | return error; |
74 | ASSERT(nmap >= 1); | 221 | ASSERT(nmap >= 1); |
75 | 222 | ||
76 | for (i = 0; (i < nmap) && (valuelen > 0); i++) { | 223 | for (i = 0; (i < nmap) && (valuelen > 0); i++) { |
224 | int byte_cnt; | ||
225 | char *src; | ||
226 | |||
77 | ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && | 227 | ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && |
78 | (map[i].br_startblock != HOLESTARTBLOCK)); | 228 | (map[i].br_startblock != HOLESTARTBLOCK)); |
79 | dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); | 229 | dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); |
80 | blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); | 230 | blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); |
81 | error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, | 231 | error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, |
82 | dblkno, blkcnt, 0, &bp, NULL); | 232 | dblkno, blkcnt, 0, &bp, |
233 | &xfs_attr3_rmt_buf_ops); | ||
83 | if (error) | 234 | if (error) |
84 | return(error); | 235 | return error; |
236 | |||
237 | byte_cnt = min_t(int, valuelen, BBTOB(bp->b_length)); | ||
238 | byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, byte_cnt); | ||
85 | 239 | ||
86 | tmp = min_t(int, valuelen, BBTOB(bp->b_length)); | 240 | src = bp->b_addr; |
87 | xfs_buf_iomove(bp, 0, tmp, dst, XBRW_READ); | 241 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
242 | if (!xfs_attr3_rmt_hdr_ok(mp, args->dp->i_ino, | ||
243 | offset, byte_cnt, bp)) { | ||
244 | xfs_alert(mp, | ||
245 | "remote attribute header does not match required off/len/owner (0x%x/Ox%x,0x%llx)", | ||
246 | offset, byte_cnt, args->dp->i_ino); | ||
247 | xfs_buf_relse(bp); | ||
248 | return EFSCORRUPTED; | ||
249 | |||
250 | } | ||
251 | |||
252 | src += sizeof(struct xfs_attr3_rmt_hdr); | ||
253 | } | ||
254 | |||
255 | memcpy(dst, src, byte_cnt); | ||
88 | xfs_buf_relse(bp); | 256 | xfs_buf_relse(bp); |
89 | dst += tmp; | 257 | |
90 | valuelen -= tmp; | 258 | offset += byte_cnt; |
259 | dst += byte_cnt; | ||
260 | valuelen -= byte_cnt; | ||
91 | 261 | ||
92 | lblkno += map[i].br_blockcount; | 262 | lblkno += map[i].br_blockcount; |
93 | } | 263 | } |
94 | } | 264 | } |
95 | ASSERT(valuelen == 0); | 265 | ASSERT(valuelen == 0); |
96 | return(0); | 266 | return 0; |
97 | } | 267 | } |
98 | 268 | ||
99 | /* | 269 | /* |
@@ -101,35 +271,49 @@ xfs_attr_rmtval_get(xfs_da_args_t *args) | |||
101 | * that we have defined for it. | 271 | * that we have defined for it. |
102 | */ | 272 | */ |
103 | int | 273 | int |
104 | xfs_attr_rmtval_set(xfs_da_args_t *args) | 274 | xfs_attr_rmtval_set( |
275 | struct xfs_da_args *args) | ||
105 | { | 276 | { |
106 | xfs_mount_t *mp; | 277 | struct xfs_inode *dp = args->dp; |
107 | xfs_fileoff_t lfileoff; | 278 | struct xfs_mount *mp = dp->i_mount; |
108 | xfs_inode_t *dp; | 279 | struct xfs_bmbt_irec map; |
109 | xfs_bmbt_irec_t map; | 280 | struct xfs_buf *bp; |
110 | xfs_daddr_t dblkno; | 281 | xfs_daddr_t dblkno; |
111 | void *src; | 282 | xfs_dablk_t lblkno; |
112 | xfs_buf_t *bp; | 283 | xfs_fileoff_t lfileoff = 0; |
113 | xfs_dablk_t lblkno; | 284 | void *src = args->value; |
114 | int blkcnt, valuelen, nmap, error, tmp, committed; | 285 | int blkcnt; |
286 | int valuelen; | ||
287 | int nmap; | ||
288 | int error; | ||
289 | int hdrcnt = 0; | ||
290 | bool crcs = xfs_sb_version_hascrc(&mp->m_sb); | ||
291 | int offset = 0; | ||
115 | 292 | ||
116 | trace_xfs_attr_rmtval_set(args); | 293 | trace_xfs_attr_rmtval_set(args); |
117 | 294 | ||
118 | dp = args->dp; | ||
119 | mp = dp->i_mount; | ||
120 | src = args->value; | ||
121 | |||
122 | /* | 295 | /* |
123 | * Find a "hole" in the attribute address space large enough for | 296 | * Find a "hole" in the attribute address space large enough for |
124 | * us to drop the new attribute's value into. | 297 | * us to drop the new attribute's value into. Because CRC enable |
298 | * attributes have headers, we can't just do a straight byte to FSB | ||
299 | * conversion. We calculate the worst case block count in this case | ||
300 | * and we may not need that many, so we have to handle this when | ||
301 | * allocating the blocks below. | ||
125 | */ | 302 | */ |
126 | blkcnt = XFS_B_TO_FSB(mp, args->valuelen); | 303 | if (!crcs) |
127 | lfileoff = 0; | 304 | blkcnt = XFS_B_TO_FSB(mp, args->valuelen); |
305 | else | ||
306 | blkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen); | ||
307 | |||
128 | error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, | 308 | error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, |
129 | XFS_ATTR_FORK); | 309 | XFS_ATTR_FORK); |
130 | if (error) { | 310 | if (error) |
131 | return(error); | 311 | return error; |
132 | } | 312 | |
313 | /* Start with the attribute data. We'll allocate the rest afterwards. */ | ||
314 | if (crcs) | ||
315 | blkcnt = XFS_B_TO_FSB(mp, args->valuelen); | ||
316 | |||
133 | args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; | 317 | args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; |
134 | args->rmtblkcnt = blkcnt; | 318 | args->rmtblkcnt = blkcnt; |
135 | 319 | ||
@@ -137,6 +321,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) | |||
137 | * Roll through the "value", allocating blocks on disk as required. | 321 | * Roll through the "value", allocating blocks on disk as required. |
138 | */ | 322 | */ |
139 | while (blkcnt > 0) { | 323 | while (blkcnt > 0) { |
324 | int committed; | ||
325 | |||
140 | /* | 326 | /* |
141 | * Allocate a single extent, up to the size of the value. | 327 | * Allocate a single extent, up to the size of the value. |
142 | */ | 328 | */ |
@@ -170,6 +356,27 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) | |||
170 | (map.br_startblock != HOLESTARTBLOCK)); | 356 | (map.br_startblock != HOLESTARTBLOCK)); |
171 | lblkno += map.br_blockcount; | 357 | lblkno += map.br_blockcount; |
172 | blkcnt -= map.br_blockcount; | 358 | blkcnt -= map.br_blockcount; |
359 | hdrcnt++; | ||
360 | |||
361 | /* | ||
362 | * If we have enough blocks for the attribute data, calculate | ||
363 | * how many extra blocks we need for headers. We might run | ||
364 | * through this multiple times in the case that the additional | ||
365 | * headers in the blocks needed for the data fragments spills | ||
366 | * into requiring more blocks. e.g. for 512 byte blocks, we'll | ||
367 | * spill for another block every 9 headers we require in this | ||
368 | * loop. | ||
369 | */ | ||
370 | |||
371 | if (crcs && blkcnt == 0) { | ||
372 | int total_len; | ||
373 | |||
374 | total_len = args->valuelen + | ||
375 | hdrcnt * sizeof(struct xfs_attr3_rmt_hdr); | ||
376 | blkcnt = XFS_B_TO_FSB(mp, total_len); | ||
377 | blkcnt -= args->rmtblkcnt; | ||
378 | args->rmtblkcnt += blkcnt; | ||
379 | } | ||
173 | 380 | ||
174 | /* | 381 | /* |
175 | * Start the next trans in the chain. | 382 | * Start the next trans in the chain. |
@@ -188,7 +395,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) | |||
188 | lblkno = args->rmtblkno; | 395 | lblkno = args->rmtblkno; |
189 | valuelen = args->valuelen; | 396 | valuelen = args->valuelen; |
190 | while (valuelen > 0) { | 397 | while (valuelen > 0) { |
191 | int buflen; | 398 | int byte_cnt; |
399 | char *buf; | ||
192 | 400 | ||
193 | /* | 401 | /* |
194 | * Try to remember where we decided to put the value. | 402 | * Try to remember where we decided to put the value. |
@@ -210,24 +418,38 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) | |||
210 | bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt, 0); | 418 | bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt, 0); |
211 | if (!bp) | 419 | if (!bp) |
212 | return ENOMEM; | 420 | return ENOMEM; |
421 | bp->b_ops = &xfs_attr3_rmt_buf_ops; | ||
422 | |||
423 | byte_cnt = BBTOB(bp->b_length); | ||
424 | byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, byte_cnt); | ||
425 | if (valuelen < byte_cnt) { | ||
426 | byte_cnt = valuelen; | ||
427 | } | ||
428 | |||
429 | buf = bp->b_addr; | ||
430 | buf += xfs_attr3_rmt_hdr_set(mp, dp->i_ino, offset, | ||
431 | byte_cnt, bp); | ||
432 | memcpy(buf, src, byte_cnt); | ||
213 | 433 | ||
214 | buflen = BBTOB(bp->b_length); | 434 | if (byte_cnt < BBTOB(bp->b_length)) |
215 | tmp = min_t(int, valuelen, buflen); | 435 | xfs_buf_zero(bp, byte_cnt, |
216 | xfs_buf_iomove(bp, 0, tmp, src, XBRW_WRITE); | 436 | BBTOB(bp->b_length) - byte_cnt); |
217 | if (tmp < buflen) | ||
218 | xfs_buf_zero(bp, tmp, buflen - tmp); | ||
219 | 437 | ||
220 | error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ | 438 | error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ |
221 | xfs_buf_relse(bp); | 439 | xfs_buf_relse(bp); |
222 | if (error) | 440 | if (error) |
223 | return error; | 441 | return error; |
224 | src += tmp; | 442 | |
225 | valuelen -= tmp; | 443 | src += byte_cnt; |
444 | valuelen -= byte_cnt; | ||
445 | offset += byte_cnt; | ||
446 | hdrcnt--; | ||
226 | 447 | ||
227 | lblkno += map.br_blockcount; | 448 | lblkno += map.br_blockcount; |
228 | } | 449 | } |
229 | ASSERT(valuelen == 0); | 450 | ASSERT(valuelen == 0); |
230 | return(0); | 451 | ASSERT(hdrcnt == 0); |
452 | return 0; | ||
231 | } | 453 | } |
232 | 454 | ||
233 | /* | 455 | /* |
@@ -306,7 +528,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) | |||
306 | ASSERT(committed); | 528 | ASSERT(committed); |
307 | args->trans = NULL; | 529 | args->trans = NULL; |
308 | xfs_bmap_cancel(args->flist); | 530 | xfs_bmap_cancel(args->flist); |
309 | return(error); | 531 | return error; |
310 | } | 532 | } |
311 | 533 | ||
312 | /* | 534 | /* |
diff --git a/fs/xfs/xfs_attr_remote.h b/fs/xfs/xfs_attr_remote.h index 2a34b9a0813e..0ca8d9a1fa03 100644 --- a/fs/xfs/xfs_attr_remote.h +++ b/fs/xfs/xfs_attr_remote.h | |||
@@ -18,6 +18,25 @@ | |||
18 | #ifndef __XFS_ATTR_REMOTE_H__ | 18 | #ifndef __XFS_ATTR_REMOTE_H__ |
19 | #define __XFS_ATTR_REMOTE_H__ | 19 | #define __XFS_ATTR_REMOTE_H__ |
20 | 20 | ||
21 | #define XFS_ATTR3_RMT_MAGIC 0x5841524d /* XARM */ | ||
22 | |||
23 | struct xfs_attr3_rmt_hdr { | ||
24 | __be32 rm_magic; | ||
25 | __be32 rm_offset; | ||
26 | __be32 rm_bytes; | ||
27 | __be32 rm_crc; | ||
28 | uuid_t rm_uuid; | ||
29 | __be64 rm_owner; | ||
30 | __be64 rm_blkno; | ||
31 | __be64 rm_lsn; | ||
32 | }; | ||
33 | |||
34 | #define XFS_ATTR3_RMT_CRC_OFF offsetof(struct xfs_attr3_rmt_hdr, rm_crc) | ||
35 | |||
36 | #define XFS_ATTR3_RMT_BUF_SPACE(mp, bufsize) \ | ||
37 | ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ | ||
38 | sizeof(struct xfs_attr3_rmt_hdr) : 0)) | ||
39 | |||
21 | int xfs_attr_rmtval_get(struct xfs_da_args *args); | 40 | int xfs_attr_rmtval_get(struct xfs_da_args *args); |
22 | int xfs_attr_rmtval_set(struct xfs_da_args *args); | 41 | int xfs_attr_rmtval_set(struct xfs_da_args *args); |
23 | int xfs_attr_rmtval_remove(struct xfs_da_args *args); | 42 | int xfs_attr_rmtval_remove(struct xfs_da_args *args); |