xref: /openbmc/linux/fs/xfs/xfs_attr_list.c (revision 93d90ad7)
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_format.h"
22 #include "xfs_log_format.h"
23 #include "xfs_trans_resv.h"
24 #include "xfs_bit.h"
25 #include "xfs_mount.h"
26 #include "xfs_da_format.h"
27 #include "xfs_da_btree.h"
28 #include "xfs_inode.h"
29 #include "xfs_trans.h"
30 #include "xfs_inode_item.h"
31 #include "xfs_bmap.h"
32 #include "xfs_attr.h"
33 #include "xfs_attr_sf.h"
34 #include "xfs_attr_remote.h"
35 #include "xfs_attr_leaf.h"
36 #include "xfs_error.h"
37 #include "xfs_trace.h"
38 #include "xfs_buf_item.h"
39 #include "xfs_cksum.h"
40 #include "xfs_dir2.h"
41 
42 STATIC int
43 xfs_attr_shortform_compare(const void *a, const void *b)
44 {
45 	xfs_attr_sf_sort_t *sa, *sb;
46 
47 	sa = (xfs_attr_sf_sort_t *)a;
48 	sb = (xfs_attr_sf_sort_t *)b;
49 	if (sa->hash < sb->hash) {
50 		return -1;
51 	} else if (sa->hash > sb->hash) {
52 		return 1;
53 	} else {
54 		return sa->entno - sb->entno;
55 	}
56 }
57 
58 #define XFS_ISRESET_CURSOR(cursor) \
59 	(!((cursor)->initted) && !((cursor)->hashval) && \
60 	 !((cursor)->blkno) && !((cursor)->offset))
61 /*
62  * Copy out entries of shortform attribute lists for attr_list().
63  * Shortform attribute lists are not stored in hashval sorted order.
64  * If the output buffer is not large enough to hold them all, then we
65  * we have to calculate each entries' hashvalue and sort them before
66  * we can begin returning them to the user.
67  */
68 int
69 xfs_attr_shortform_list(xfs_attr_list_context_t *context)
70 {
71 	attrlist_cursor_kern_t *cursor;
72 	xfs_attr_sf_sort_t *sbuf, *sbp;
73 	xfs_attr_shortform_t *sf;
74 	xfs_attr_sf_entry_t *sfe;
75 	xfs_inode_t *dp;
76 	int sbsize, nsbuf, count, i;
77 	int error;
78 
79 	ASSERT(context != NULL);
80 	dp = context->dp;
81 	ASSERT(dp != NULL);
82 	ASSERT(dp->i_afp != NULL);
83 	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
84 	ASSERT(sf != NULL);
85 	if (!sf->hdr.count)
86 		return 0;
87 	cursor = context->cursor;
88 	ASSERT(cursor != NULL);
89 
90 	trace_xfs_attr_list_sf(context);
91 
92 	/*
93 	 * If the buffer is large enough and the cursor is at the start,
94 	 * do not bother with sorting since we will return everything in
95 	 * one buffer and another call using the cursor won't need to be
96 	 * made.
97 	 * Note the generous fudge factor of 16 overhead bytes per entry.
98 	 * If bufsize is zero then put_listent must be a search function
99 	 * and can just scan through what we have.
100 	 */
101 	if (context->bufsize == 0 ||
102 	    (XFS_ISRESET_CURSOR(cursor) &&
103              (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
104 		for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
105 			error = context->put_listent(context,
106 					   sfe->flags,
107 					   sfe->nameval,
108 					   (int)sfe->namelen,
109 					   (int)sfe->valuelen,
110 					   &sfe->nameval[sfe->namelen]);
111 
112 			/*
113 			 * Either search callback finished early or
114 			 * didn't fit it all in the buffer after all.
115 			 */
116 			if (context->seen_enough)
117 				break;
118 
119 			if (error)
120 				return error;
121 			sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
122 		}
123 		trace_xfs_attr_list_sf_all(context);
124 		return 0;
125 	}
126 
127 	/* do no more for a search callback */
128 	if (context->bufsize == 0)
129 		return 0;
130 
131 	/*
132 	 * It didn't all fit, so we have to sort everything on hashval.
133 	 */
134 	sbsize = sf->hdr.count * sizeof(*sbuf);
135 	sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP | KM_NOFS);
136 
137 	/*
138 	 * Scan the attribute list for the rest of the entries, storing
139 	 * the relevant info from only those that match into a buffer.
140 	 */
141 	nsbuf = 0;
142 	for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
143 		if (unlikely(
144 		    ((char *)sfe < (char *)sf) ||
145 		    ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {
146 			XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
147 					     XFS_ERRLEVEL_LOW,
148 					     context->dp->i_mount, sfe);
149 			kmem_free(sbuf);
150 			return -EFSCORRUPTED;
151 		}
152 
153 		sbp->entno = i;
154 		sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
155 		sbp->name = sfe->nameval;
156 		sbp->namelen = sfe->namelen;
157 		/* These are bytes, and both on-disk, don't endian-flip */
158 		sbp->valuelen = sfe->valuelen;
159 		sbp->flags = sfe->flags;
160 		sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
161 		sbp++;
162 		nsbuf++;
163 	}
164 
165 	/*
166 	 * Sort the entries on hash then entno.
167 	 */
168 	xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
169 
170 	/*
171 	 * Re-find our place IN THE SORTED LIST.
172 	 */
173 	count = 0;
174 	cursor->initted = 1;
175 	cursor->blkno = 0;
176 	for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
177 		if (sbp->hash == cursor->hashval) {
178 			if (cursor->offset == count) {
179 				break;
180 			}
181 			count++;
182 		} else if (sbp->hash > cursor->hashval) {
183 			break;
184 		}
185 	}
186 	if (i == nsbuf) {
187 		kmem_free(sbuf);
188 		return 0;
189 	}
190 
191 	/*
192 	 * Loop putting entries into the user buffer.
193 	 */
194 	for ( ; i < nsbuf; i++, sbp++) {
195 		if (cursor->hashval != sbp->hash) {
196 			cursor->hashval = sbp->hash;
197 			cursor->offset = 0;
198 		}
199 		error = context->put_listent(context,
200 					sbp->flags,
201 					sbp->name,
202 					sbp->namelen,
203 					sbp->valuelen,
204 					&sbp->name[sbp->namelen]);
205 		if (error)
206 			return error;
207 		if (context->seen_enough)
208 			break;
209 		cursor->offset++;
210 	}
211 
212 	kmem_free(sbuf);
213 	return 0;
214 }
215 
216 STATIC int
217 xfs_attr_node_list(xfs_attr_list_context_t *context)
218 {
219 	attrlist_cursor_kern_t *cursor;
220 	xfs_attr_leafblock_t *leaf;
221 	xfs_da_intnode_t *node;
222 	struct xfs_attr3_icleaf_hdr leafhdr;
223 	struct xfs_da3_icnode_hdr nodehdr;
224 	struct xfs_da_node_entry *btree;
225 	int error, i;
226 	struct xfs_buf *bp;
227 	struct xfs_inode	*dp = context->dp;
228 
229 	trace_xfs_attr_node_list(context);
230 
231 	cursor = context->cursor;
232 	cursor->initted = 1;
233 
234 	/*
235 	 * Do all sorts of validation on the passed-in cursor structure.
236 	 * If anything is amiss, ignore the cursor and look up the hashval
237 	 * starting from the btree root.
238 	 */
239 	bp = NULL;
240 	if (cursor->blkno > 0) {
241 		error = xfs_da3_node_read(NULL, dp, cursor->blkno, -1,
242 					      &bp, XFS_ATTR_FORK);
243 		if ((error != 0) && (error != -EFSCORRUPTED))
244 			return error;
245 		if (bp) {
246 			struct xfs_attr_leaf_entry *entries;
247 
248 			node = bp->b_addr;
249 			switch (be16_to_cpu(node->hdr.info.magic)) {
250 			case XFS_DA_NODE_MAGIC:
251 			case XFS_DA3_NODE_MAGIC:
252 				trace_xfs_attr_list_wrong_blk(context);
253 				xfs_trans_brelse(NULL, bp);
254 				bp = NULL;
255 				break;
256 			case XFS_ATTR_LEAF_MAGIC:
257 			case XFS_ATTR3_LEAF_MAGIC:
258 				leaf = bp->b_addr;
259 				xfs_attr3_leaf_hdr_from_disk(&leafhdr, leaf);
260 				entries = xfs_attr3_leaf_entryp(leaf);
261 				if (cursor->hashval > be32_to_cpu(
262 						entries[leafhdr.count - 1].hashval)) {
263 					trace_xfs_attr_list_wrong_blk(context);
264 					xfs_trans_brelse(NULL, bp);
265 					bp = NULL;
266 				} else if (cursor->hashval <= be32_to_cpu(
267 						entries[0].hashval)) {
268 					trace_xfs_attr_list_wrong_blk(context);
269 					xfs_trans_brelse(NULL, bp);
270 					bp = NULL;
271 				}
272 				break;
273 			default:
274 				trace_xfs_attr_list_wrong_blk(context);
275 				xfs_trans_brelse(NULL, bp);
276 				bp = NULL;
277 			}
278 		}
279 	}
280 
281 	/*
282 	 * We did not find what we expected given the cursor's contents,
283 	 * so we start from the top and work down based on the hash value.
284 	 * Note that start of node block is same as start of leaf block.
285 	 */
286 	if (bp == NULL) {
287 		cursor->blkno = 0;
288 		for (;;) {
289 			__uint16_t magic;
290 
291 			error = xfs_da3_node_read(NULL, dp,
292 						      cursor->blkno, -1, &bp,
293 						      XFS_ATTR_FORK);
294 			if (error)
295 				return error;
296 			node = bp->b_addr;
297 			magic = be16_to_cpu(node->hdr.info.magic);
298 			if (magic == XFS_ATTR_LEAF_MAGIC ||
299 			    magic == XFS_ATTR3_LEAF_MAGIC)
300 				break;
301 			if (magic != XFS_DA_NODE_MAGIC &&
302 			    magic != XFS_DA3_NODE_MAGIC) {
303 				XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)",
304 						     XFS_ERRLEVEL_LOW,
305 						     context->dp->i_mount,
306 						     node);
307 				xfs_trans_brelse(NULL, bp);
308 				return -EFSCORRUPTED;
309 			}
310 
311 			dp->d_ops->node_hdr_from_disk(&nodehdr, node);
312 			btree = dp->d_ops->node_tree_p(node);
313 			for (i = 0; i < nodehdr.count; btree++, i++) {
314 				if (cursor->hashval
315 						<= be32_to_cpu(btree->hashval)) {
316 					cursor->blkno = be32_to_cpu(btree->before);
317 					trace_xfs_attr_list_node_descend(context,
318 									 btree);
319 					break;
320 				}
321 			}
322 			if (i == nodehdr.count) {
323 				xfs_trans_brelse(NULL, bp);
324 				return 0;
325 			}
326 			xfs_trans_brelse(NULL, bp);
327 		}
328 	}
329 	ASSERT(bp != NULL);
330 
331 	/*
332 	 * Roll upward through the blocks, processing each leaf block in
333 	 * order.  As long as there is space in the result buffer, keep
334 	 * adding the information.
335 	 */
336 	for (;;) {
337 		leaf = bp->b_addr;
338 		error = xfs_attr3_leaf_list_int(bp, context);
339 		if (error) {
340 			xfs_trans_brelse(NULL, bp);
341 			return error;
342 		}
343 		xfs_attr3_leaf_hdr_from_disk(&leafhdr, leaf);
344 		if (context->seen_enough || leafhdr.forw == 0)
345 			break;
346 		cursor->blkno = leafhdr.forw;
347 		xfs_trans_brelse(NULL, bp);
348 		error = xfs_attr3_leaf_read(NULL, dp, cursor->blkno, -1, &bp);
349 		if (error)
350 			return error;
351 	}
352 	xfs_trans_brelse(NULL, bp);
353 	return 0;
354 }
355 
356 /*
357  * Copy out attribute list entries for attr_list(), for leaf attribute lists.
358  */
359 int
360 xfs_attr3_leaf_list_int(
361 	struct xfs_buf			*bp,
362 	struct xfs_attr_list_context	*context)
363 {
364 	struct attrlist_cursor_kern	*cursor;
365 	struct xfs_attr_leafblock	*leaf;
366 	struct xfs_attr3_icleaf_hdr	ichdr;
367 	struct xfs_attr_leaf_entry	*entries;
368 	struct xfs_attr_leaf_entry	*entry;
369 	int				retval;
370 	int				i;
371 
372 	trace_xfs_attr_list_leaf(context);
373 
374 	leaf = bp->b_addr;
375 	xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
376 	entries = xfs_attr3_leaf_entryp(leaf);
377 
378 	cursor = context->cursor;
379 	cursor->initted = 1;
380 
381 	/*
382 	 * Re-find our place in the leaf block if this is a new syscall.
383 	 */
384 	if (context->resynch) {
385 		entry = &entries[0];
386 		for (i = 0; i < ichdr.count; entry++, i++) {
387 			if (be32_to_cpu(entry->hashval) == cursor->hashval) {
388 				if (cursor->offset == context->dupcnt) {
389 					context->dupcnt = 0;
390 					break;
391 				}
392 				context->dupcnt++;
393 			} else if (be32_to_cpu(entry->hashval) >
394 					cursor->hashval) {
395 				context->dupcnt = 0;
396 				break;
397 			}
398 		}
399 		if (i == ichdr.count) {
400 			trace_xfs_attr_list_notfound(context);
401 			return 0;
402 		}
403 	} else {
404 		entry = &entries[0];
405 		i = 0;
406 	}
407 	context->resynch = 0;
408 
409 	/*
410 	 * We have found our place, start copying out the new attributes.
411 	 */
412 	retval = 0;
413 	for (; i < ichdr.count; entry++, i++) {
414 		if (be32_to_cpu(entry->hashval) != cursor->hashval) {
415 			cursor->hashval = be32_to_cpu(entry->hashval);
416 			cursor->offset = 0;
417 		}
418 
419 		if (entry->flags & XFS_ATTR_INCOMPLETE)
420 			continue;		/* skip incomplete entries */
421 
422 		if (entry->flags & XFS_ATTR_LOCAL) {
423 			xfs_attr_leaf_name_local_t *name_loc =
424 				xfs_attr3_leaf_name_local(leaf, i);
425 
426 			retval = context->put_listent(context,
427 						entry->flags,
428 						name_loc->nameval,
429 						(int)name_loc->namelen,
430 						be16_to_cpu(name_loc->valuelen),
431 						&name_loc->nameval[name_loc->namelen]);
432 			if (retval)
433 				return retval;
434 		} else {
435 			xfs_attr_leaf_name_remote_t *name_rmt =
436 				xfs_attr3_leaf_name_remote(leaf, i);
437 
438 			int valuelen = be32_to_cpu(name_rmt->valuelen);
439 
440 			if (context->put_value) {
441 				xfs_da_args_t args;
442 
443 				memset((char *)&args, 0, sizeof(args));
444 				args.geo = context->dp->i_mount->m_attr_geo;
445 				args.dp = context->dp;
446 				args.whichfork = XFS_ATTR_FORK;
447 				args.valuelen = valuelen;
448 				args.rmtvaluelen = valuelen;
449 				args.value = kmem_alloc(valuelen, KM_SLEEP | KM_NOFS);
450 				args.rmtblkno = be32_to_cpu(name_rmt->valueblk);
451 				args.rmtblkcnt = xfs_attr3_rmt_blocks(
452 							args.dp->i_mount, valuelen);
453 				retval = xfs_attr_rmtval_get(&args);
454 				if (retval)
455 					return retval;
456 				retval = context->put_listent(context,
457 						entry->flags,
458 						name_rmt->name,
459 						(int)name_rmt->namelen,
460 						valuelen,
461 						args.value);
462 				kmem_free(args.value);
463 			} else {
464 				retval = context->put_listent(context,
465 						entry->flags,
466 						name_rmt->name,
467 						(int)name_rmt->namelen,
468 						valuelen,
469 						NULL);
470 			}
471 			if (retval)
472 				return retval;
473 		}
474 		if (context->seen_enough)
475 			break;
476 		cursor->offset++;
477 	}
478 	trace_xfs_attr_list_leaf_end(context);
479 	return retval;
480 }
481 
482 /*
483  * Copy out attribute entries for attr_list(), for leaf attribute lists.
484  */
485 STATIC int
486 xfs_attr_leaf_list(xfs_attr_list_context_t *context)
487 {
488 	int error;
489 	struct xfs_buf *bp;
490 
491 	trace_xfs_attr_leaf_list(context);
492 
493 	context->cursor->blkno = 0;
494 	error = xfs_attr3_leaf_read(NULL, context->dp, 0, -1, &bp);
495 	if (error)
496 		return error;
497 
498 	error = xfs_attr3_leaf_list_int(bp, context);
499 	xfs_trans_brelse(NULL, bp);
500 	return error;
501 }
502 
503 int
504 xfs_attr_list_int(
505 	xfs_attr_list_context_t *context)
506 {
507 	int error;
508 	xfs_inode_t *dp = context->dp;
509 	uint		lock_mode;
510 
511 	XFS_STATS_INC(xs_attr_list);
512 
513 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
514 		return -EIO;
515 
516 	/*
517 	 * Decide on what work routines to call based on the inode size.
518 	 */
519 	lock_mode = xfs_ilock_attr_map_shared(dp);
520 	if (!xfs_inode_hasattr(dp)) {
521 		error = 0;
522 	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
523 		error = xfs_attr_shortform_list(context);
524 	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
525 		error = xfs_attr_leaf_list(context);
526 	} else {
527 		error = xfs_attr_node_list(context);
528 	}
529 	xfs_iunlock(dp, lock_mode);
530 	return error;
531 }
532 
533 #define	ATTR_ENTBASESIZE		/* minimum bytes used by an attr */ \
534 	(((struct attrlist_ent *) 0)->a_name - (char *) 0)
535 #define	ATTR_ENTSIZE(namelen)		/* actual bytes used by an attr */ \
536 	((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
537 	 & ~(sizeof(u_int32_t)-1))
538 
539 /*
540  * Format an attribute and copy it out to the user's buffer.
541  * Take care to check values and protect against them changing later,
542  * we may be reading them directly out of a user buffer.
543  */
544 STATIC int
545 xfs_attr_put_listent(
546 	xfs_attr_list_context_t *context,
547 	int		flags,
548 	unsigned char	*name,
549 	int		namelen,
550 	int		valuelen,
551 	unsigned char	*value)
552 {
553 	struct attrlist *alist = (struct attrlist *)context->alist;
554 	attrlist_ent_t *aep;
555 	int arraytop;
556 
557 	ASSERT(!(context->flags & ATTR_KERNOVAL));
558 	ASSERT(context->count >= 0);
559 	ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
560 	ASSERT(context->firstu >= sizeof(*alist));
561 	ASSERT(context->firstu <= context->bufsize);
562 
563 	/*
564 	 * Only list entries in the right namespace.
565 	 */
566 	if (((context->flags & ATTR_SECURE) == 0) !=
567 	    ((flags & XFS_ATTR_SECURE) == 0))
568 		return 0;
569 	if (((context->flags & ATTR_ROOT) == 0) !=
570 	    ((flags & XFS_ATTR_ROOT) == 0))
571 		return 0;
572 
573 	arraytop = sizeof(*alist) +
574 			context->count * sizeof(alist->al_offset[0]);
575 	context->firstu -= ATTR_ENTSIZE(namelen);
576 	if (context->firstu < arraytop) {
577 		trace_xfs_attr_list_full(context);
578 		alist->al_more = 1;
579 		context->seen_enough = 1;
580 		return 1;
581 	}
582 
583 	aep = (attrlist_ent_t *)&context->alist[context->firstu];
584 	aep->a_valuelen = valuelen;
585 	memcpy(aep->a_name, name, namelen);
586 	aep->a_name[namelen] = 0;
587 	alist->al_offset[context->count++] = context->firstu;
588 	alist->al_count = context->count;
589 	trace_xfs_attr_list_add(context);
590 	return 0;
591 }
592 
593 /*
594  * Generate a list of extended attribute names and optionally
595  * also value lengths.  Positive return value follows the XFS
596  * convention of being an error, zero or negative return code
597  * is the length of the buffer returned (negated), indicating
598  * success.
599  */
600 int
601 xfs_attr_list(
602 	xfs_inode_t	*dp,
603 	char		*buffer,
604 	int		bufsize,
605 	int		flags,
606 	attrlist_cursor_kern_t *cursor)
607 {
608 	xfs_attr_list_context_t context;
609 	struct attrlist *alist;
610 	int error;
611 
612 	/*
613 	 * Validate the cursor.
614 	 */
615 	if (cursor->pad1 || cursor->pad2)
616 		return -EINVAL;
617 	if ((cursor->initted == 0) &&
618 	    (cursor->hashval || cursor->blkno || cursor->offset))
619 		return -EINVAL;
620 
621 	/*
622 	 * Check for a properly aligned buffer.
623 	 */
624 	if (((long)buffer) & (sizeof(int)-1))
625 		return -EFAULT;
626 	if (flags & ATTR_KERNOVAL)
627 		bufsize = 0;
628 
629 	/*
630 	 * Initialize the output buffer.
631 	 */
632 	memset(&context, 0, sizeof(context));
633 	context.dp = dp;
634 	context.cursor = cursor;
635 	context.resynch = 1;
636 	context.flags = flags;
637 	context.alist = buffer;
638 	context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
639 	context.firstu = context.bufsize;
640 	context.put_listent = xfs_attr_put_listent;
641 
642 	alist = (struct attrlist *)context.alist;
643 	alist->al_count = 0;
644 	alist->al_more = 0;
645 	alist->al_offset[0] = context.bufsize;
646 
647 	error = xfs_attr_list_int(&context);
648 	ASSERT(error <= 0);
649 	return error;
650 }
651