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