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