]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxfs/xfs_attr_remote.c
xfs: rename flist/free_list to dfops
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_attr_remote.c
1 /*
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * Copyright (c) 2013 Red Hat, Inc.
4 * All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 #include "libxfs_priv.h"
20 #include "xfs_fs.h"
21 #include "xfs_shared.h"
22 #include "xfs_format.h"
23 #include "xfs_log_format.h"
24 #include "xfs_trans_resv.h"
25 #include "xfs_bit.h"
26 #include "xfs_mount.h"
27 #include "xfs_defer.h"
28 #include "xfs_da_format.h"
29 #include "xfs_da_btree.h"
30 #include "xfs_inode.h"
31 #include "xfs_alloc.h"
32 #include "xfs_trans.h"
33 #include "xfs_bmap.h"
34 #include "xfs_attr_leaf.h"
35 #include "xfs_attr_remote.h"
36 #include "xfs_trans_space.h"
37 #include "xfs_trace.h"
38 #include "xfs_cksum.h"
39
40 #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */
41
42 /*
43 * Each contiguous block has a header, so it is not just a simple attribute
44 * length to FSB conversion.
45 */
46 int
47 xfs_attr3_rmt_blocks(
48 struct xfs_mount *mp,
49 int attrlen)
50 {
51 if (xfs_sb_version_hascrc(&mp->m_sb)) {
52 int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
53 return (attrlen + buflen - 1) / buflen;
54 }
55 return XFS_B_TO_FSB(mp, attrlen);
56 }
57
58 /*
59 * Checking of the remote attribute header is split into two parts. The verifier
60 * does CRC, location and bounds checking, the unpacking function checks the
61 * attribute parameters and owner.
62 */
63 static bool
64 xfs_attr3_rmt_hdr_ok(
65 void *ptr,
66 xfs_ino_t ino,
67 uint32_t offset,
68 uint32_t size,
69 xfs_daddr_t bno)
70 {
71 struct xfs_attr3_rmt_hdr *rmt = ptr;
72
73 if (bno != be64_to_cpu(rmt->rm_blkno))
74 return false;
75 if (offset != be32_to_cpu(rmt->rm_offset))
76 return false;
77 if (size != be32_to_cpu(rmt->rm_bytes))
78 return false;
79 if (ino != be64_to_cpu(rmt->rm_owner))
80 return false;
81
82 /* ok */
83 return true;
84 }
85
86 static bool
87 xfs_attr3_rmt_verify(
88 struct xfs_mount *mp,
89 void *ptr,
90 int fsbsize,
91 xfs_daddr_t bno)
92 {
93 struct xfs_attr3_rmt_hdr *rmt = ptr;
94
95 if (!xfs_sb_version_hascrc(&mp->m_sb))
96 return false;
97 if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
98 return false;
99 if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
100 return false;
101 if (be64_to_cpu(rmt->rm_blkno) != bno)
102 return false;
103 if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
104 return false;
105 if (be32_to_cpu(rmt->rm_offset) +
106 be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
107 return false;
108 if (rmt->rm_owner == 0)
109 return false;
110
111 return true;
112 }
113
114 static void
115 xfs_attr3_rmt_read_verify(
116 struct xfs_buf *bp)
117 {
118 struct xfs_mount *mp = bp->b_target->bt_mount;
119 char *ptr;
120 int len;
121 xfs_daddr_t bno;
122 int blksize = mp->m_attr_geo->blksize;
123
124 /* no verification of non-crc buffers */
125 if (!xfs_sb_version_hascrc(&mp->m_sb))
126 return;
127
128 ptr = bp->b_addr;
129 bno = bp->b_bn;
130 len = BBTOB(bp->b_length);
131 ASSERT(len >= blksize);
132
133 while (len > 0) {
134 if (!xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
135 xfs_buf_ioerror(bp, -EFSBADCRC);
136 break;
137 }
138 if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
139 xfs_buf_ioerror(bp, -EFSCORRUPTED);
140 break;
141 }
142 len -= blksize;
143 ptr += blksize;
144 bno += BTOBB(blksize);
145 }
146
147 if (bp->b_error)
148 xfs_verifier_error(bp);
149 else
150 ASSERT(len == 0);
151 }
152
153 static void
154 xfs_attr3_rmt_write_verify(
155 struct xfs_buf *bp)
156 {
157 struct xfs_mount *mp = bp->b_target->bt_mount;
158 int blksize = mp->m_attr_geo->blksize;
159 char *ptr;
160 int len;
161 xfs_daddr_t bno;
162
163 /* no verification of non-crc buffers */
164 if (!xfs_sb_version_hascrc(&mp->m_sb))
165 return;
166
167 ptr = bp->b_addr;
168 bno = bp->b_bn;
169 len = BBTOB(bp->b_length);
170 ASSERT(len >= blksize);
171
172 while (len > 0) {
173 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
174
175 if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
176 xfs_buf_ioerror(bp, -EFSCORRUPTED);
177 xfs_verifier_error(bp);
178 return;
179 }
180
181 /*
182 * Ensure we aren't writing bogus LSNs to disk. See
183 * xfs_attr3_rmt_hdr_set() for the explanation.
184 */
185 if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
186 xfs_buf_ioerror(bp, -EFSCORRUPTED);
187 xfs_verifier_error(bp);
188 return;
189 }
190 xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
191
192 len -= blksize;
193 ptr += blksize;
194 bno += BTOBB(blksize);
195 }
196 ASSERT(len == 0);
197 }
198
199 const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
200 .name = "xfs_attr3_rmt",
201 .verify_read = xfs_attr3_rmt_read_verify,
202 .verify_write = xfs_attr3_rmt_write_verify,
203 };
204
205 STATIC int
206 xfs_attr3_rmt_hdr_set(
207 struct xfs_mount *mp,
208 void *ptr,
209 xfs_ino_t ino,
210 uint32_t offset,
211 uint32_t size,
212 xfs_daddr_t bno)
213 {
214 struct xfs_attr3_rmt_hdr *rmt = ptr;
215
216 if (!xfs_sb_version_hascrc(&mp->m_sb))
217 return 0;
218
219 rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
220 rmt->rm_offset = cpu_to_be32(offset);
221 rmt->rm_bytes = cpu_to_be32(size);
222 uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
223 rmt->rm_owner = cpu_to_be64(ino);
224 rmt->rm_blkno = cpu_to_be64(bno);
225
226 /*
227 * Remote attribute blocks are written synchronously, so we don't
228 * have an LSN that we can stamp in them that makes any sense to log
229 * recovery. To ensure that log recovery handles overwrites of these
230 * blocks sanely (i.e. once they've been freed and reallocated as some
231 * other type of metadata) we need to ensure that the LSN has a value
232 * that tells log recovery to ignore the LSN and overwrite the buffer
233 * with whatever is in it's log. To do this, we use the magic
234 * NULLCOMMITLSN to indicate that the LSN is invalid.
235 */
236 rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
237
238 return sizeof(struct xfs_attr3_rmt_hdr);
239 }
240
241 /*
242 * Helper functions to copy attribute data in and out of the one disk extents
243 */
244 STATIC int
245 xfs_attr_rmtval_copyout(
246 struct xfs_mount *mp,
247 struct xfs_buf *bp,
248 xfs_ino_t ino,
249 int *offset,
250 int *valuelen,
251 __uint8_t **dst)
252 {
253 char *src = bp->b_addr;
254 xfs_daddr_t bno = bp->b_bn;
255 int len = BBTOB(bp->b_length);
256 int blksize = mp->m_attr_geo->blksize;
257
258 ASSERT(len >= blksize);
259
260 while (len > 0 && *valuelen > 0) {
261 int hdr_size = 0;
262 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
263
264 byte_cnt = min(*valuelen, byte_cnt);
265
266 if (xfs_sb_version_hascrc(&mp->m_sb)) {
267 if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset,
268 byte_cnt, bno)) {
269 xfs_alert(mp,
270 "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
271 bno, *offset, byte_cnt, ino);
272 return -EFSCORRUPTED;
273 }
274 hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
275 }
276
277 memcpy(*dst, src + hdr_size, byte_cnt);
278
279 /* roll buffer forwards */
280 len -= blksize;
281 src += blksize;
282 bno += BTOBB(blksize);
283
284 /* roll attribute data forwards */
285 *valuelen -= byte_cnt;
286 *dst += byte_cnt;
287 *offset += byte_cnt;
288 }
289 return 0;
290 }
291
292 STATIC void
293 xfs_attr_rmtval_copyin(
294 struct xfs_mount *mp,
295 struct xfs_buf *bp,
296 xfs_ino_t ino,
297 int *offset,
298 int *valuelen,
299 __uint8_t **src)
300 {
301 char *dst = bp->b_addr;
302 xfs_daddr_t bno = bp->b_bn;
303 int len = BBTOB(bp->b_length);
304 int blksize = mp->m_attr_geo->blksize;
305
306 ASSERT(len >= blksize);
307
308 while (len > 0 && *valuelen > 0) {
309 int hdr_size;
310 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
311
312 byte_cnt = min(*valuelen, byte_cnt);
313 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
314 byte_cnt, bno);
315
316 memcpy(dst + hdr_size, *src, byte_cnt);
317
318 /*
319 * If this is the last block, zero the remainder of it.
320 * Check that we are actually the last block, too.
321 */
322 if (byte_cnt + hdr_size < blksize) {
323 ASSERT(*valuelen - byte_cnt == 0);
324 ASSERT(len == blksize);
325 memset(dst + hdr_size + byte_cnt, 0,
326 blksize - hdr_size - byte_cnt);
327 }
328
329 /* roll buffer forwards */
330 len -= blksize;
331 dst += blksize;
332 bno += BTOBB(blksize);
333
334 /* roll attribute data forwards */
335 *valuelen -= byte_cnt;
336 *src += byte_cnt;
337 *offset += byte_cnt;
338 }
339 }
340
341 /*
342 * Read the value associated with an attribute from the out-of-line buffer
343 * that we stored it in.
344 */
345 int
346 xfs_attr_rmtval_get(
347 struct xfs_da_args *args)
348 {
349 struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE];
350 struct xfs_mount *mp = args->dp->i_mount;
351 struct xfs_buf *bp;
352 xfs_dablk_t lblkno = args->rmtblkno;
353 __uint8_t *dst = args->value;
354 int valuelen;
355 int nmap;
356 int error;
357 int blkcnt = args->rmtblkcnt;
358 int i;
359 int offset = 0;
360
361 trace_xfs_attr_rmtval_get(args);
362
363 ASSERT(!(args->flags & ATTR_KERNOVAL));
364 ASSERT(args->rmtvaluelen == args->valuelen);
365
366 valuelen = args->rmtvaluelen;
367 while (valuelen > 0) {
368 nmap = ATTR_RMTVALUE_MAPSIZE;
369 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
370 blkcnt, map, &nmap,
371 XFS_BMAPI_ATTRFORK);
372 if (error)
373 return error;
374 ASSERT(nmap >= 1);
375
376 for (i = 0; (i < nmap) && (valuelen > 0); i++) {
377 xfs_daddr_t dblkno;
378 int dblkcnt;
379
380 ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
381 (map[i].br_startblock != HOLESTARTBLOCK));
382 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
383 dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
384 error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
385 dblkno, dblkcnt, 0, &bp,
386 &xfs_attr3_rmt_buf_ops);
387 if (error)
388 return error;
389
390 error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
391 &offset, &valuelen,
392 &dst);
393 xfs_buf_relse(bp);
394 if (error)
395 return error;
396
397 /* roll attribute extent map forwards */
398 lblkno += map[i].br_blockcount;
399 blkcnt -= map[i].br_blockcount;
400 }
401 }
402 ASSERT(valuelen == 0);
403 return 0;
404 }
405
406 /*
407 * Write the value associated with an attribute into the out-of-line buffer
408 * that we have defined for it.
409 */
410 int
411 xfs_attr_rmtval_set(
412 struct xfs_da_args *args)
413 {
414 struct xfs_inode *dp = args->dp;
415 struct xfs_mount *mp = dp->i_mount;
416 struct xfs_bmbt_irec map;
417 xfs_dablk_t lblkno;
418 xfs_fileoff_t lfileoff = 0;
419 __uint8_t *src = args->value;
420 int blkcnt;
421 int valuelen;
422 int nmap;
423 int error;
424 int offset = 0;
425
426 trace_xfs_attr_rmtval_set(args);
427
428 /*
429 * Find a "hole" in the attribute address space large enough for
430 * us to drop the new attribute's value into. Because CRC enable
431 * attributes have headers, we can't just do a straight byte to FSB
432 * conversion and have to take the header space into account.
433 */
434 blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
435 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
436 XFS_ATTR_FORK);
437 if (error)
438 return error;
439
440 args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
441 args->rmtblkcnt = blkcnt;
442
443 /*
444 * Roll through the "value", allocating blocks on disk as required.
445 */
446 while (blkcnt > 0) {
447 /*
448 * Allocate a single extent, up to the size of the value.
449 *
450 * Note that we have to consider this a data allocation as we
451 * write the remote attribute without logging the contents.
452 * Hence we must ensure that we aren't using blocks that are on
453 * the busy list so that we don't overwrite blocks which have
454 * recently been freed but their transactions are not yet
455 * committed to disk. If we overwrite the contents of a busy
456 * extent and then crash then the block may not contain the
457 * correct metadata after log recovery occurs.
458 */
459 xfs_defer_init(args->dfops, args->firstblock);
460 nmap = 1;
461 error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
462 blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock,
463 args->total, &map, &nmap, args->dfops);
464 if (!error)
465 error = xfs_defer_finish(&args->trans, args->dfops, dp);
466 if (error) {
467 args->trans = NULL;
468 xfs_defer_cancel(args->dfops);
469 return error;
470 }
471
472 ASSERT(nmap == 1);
473 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
474 (map.br_startblock != HOLESTARTBLOCK));
475 lblkno += map.br_blockcount;
476 blkcnt -= map.br_blockcount;
477
478 /*
479 * Start the next trans in the chain.
480 */
481 error = xfs_trans_roll(&args->trans, dp);
482 if (error)
483 return error;
484 }
485
486 /*
487 * Roll through the "value", copying the attribute value to the
488 * already-allocated blocks. Blocks are written synchronously
489 * so that we can know they are all on disk before we turn off
490 * the INCOMPLETE flag.
491 */
492 lblkno = args->rmtblkno;
493 blkcnt = args->rmtblkcnt;
494 valuelen = args->rmtvaluelen;
495 while (valuelen > 0) {
496 struct xfs_buf *bp;
497 xfs_daddr_t dblkno;
498 int dblkcnt;
499
500 ASSERT(blkcnt > 0);
501
502 xfs_defer_init(args->dfops, args->firstblock);
503 nmap = 1;
504 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
505 blkcnt, &map, &nmap,
506 XFS_BMAPI_ATTRFORK);
507 if (error)
508 return error;
509 ASSERT(nmap == 1);
510 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
511 (map.br_startblock != HOLESTARTBLOCK));
512
513 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
514 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
515
516 bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0);
517 if (!bp)
518 return -ENOMEM;
519 bp->b_ops = &xfs_attr3_rmt_buf_ops;
520
521 xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
522 &valuelen, &src);
523
524 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
525 xfs_buf_relse(bp);
526 if (error)
527 return error;
528
529
530 /* roll attribute extent map forwards */
531 lblkno += map.br_blockcount;
532 blkcnt -= map.br_blockcount;
533 }
534 ASSERT(valuelen == 0);
535 return 0;
536 }
537
538 /*
539 * Remove the value associated with an attribute by deleting the
540 * out-of-line buffer that it is stored on.
541 */
542 int
543 xfs_attr_rmtval_remove(
544 struct xfs_da_args *args)
545 {
546 struct xfs_mount *mp = args->dp->i_mount;
547 xfs_dablk_t lblkno;
548 int blkcnt;
549 int error;
550 int done;
551
552 trace_xfs_attr_rmtval_remove(args);
553
554 /*
555 * Roll through the "value", invalidating the attribute value's blocks.
556 */
557 lblkno = args->rmtblkno;
558 blkcnt = args->rmtblkcnt;
559 while (blkcnt > 0) {
560 struct xfs_bmbt_irec map;
561 struct xfs_buf *bp;
562 xfs_daddr_t dblkno;
563 int dblkcnt;
564 int nmap;
565
566 /*
567 * Try to remember where we decided to put the value.
568 */
569 nmap = 1;
570 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
571 blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
572 if (error)
573 return error;
574 ASSERT(nmap == 1);
575 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
576 (map.br_startblock != HOLESTARTBLOCK));
577
578 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
579 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
580
581 /*
582 * If the "remote" value is in the cache, remove it.
583 */
584 bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
585 if (bp) {
586 xfs_buf_stale(bp);
587 xfs_buf_relse(bp);
588 bp = NULL;
589 }
590
591 lblkno += map.br_blockcount;
592 blkcnt -= map.br_blockcount;
593 }
594
595 /*
596 * Keep de-allocating extents until the remote-value region is gone.
597 */
598 lblkno = args->rmtblkno;
599 blkcnt = args->rmtblkcnt;
600 done = 0;
601 while (!done) {
602 xfs_defer_init(args->dfops, args->firstblock);
603 error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
604 XFS_BMAPI_ATTRFORK, 1, args->firstblock,
605 args->dfops, &done);
606 if (!error)
607 error = xfs_defer_finish(&args->trans, args->dfops,
608 args->dp);
609 if (error) {
610 args->trans = NULL;
611 xfs_defer_cancel(args->dfops);
612 return error;
613 }
614
615 /*
616 * Close out trans and start the next one in the chain.
617 */
618 error = xfs_trans_roll(&args->trans, args->dp);
619 if (error)
620 return error;
621 }
622 return 0;
623 }