ba71bf4303f86e8654edf158a4a0024237e779c8
[linux-2.6-microblaze.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_IS_CORRUPT(context->dp->i_mount,
90                                            !xfs_attr_namecheck(sfe->nameval,
91                                                                sfe->namelen)))
92                                 return -EFSCORRUPTED;
93                         context->put_listent(context,
94                                              sfe->flags,
95                                              sfe->nameval,
96                                              (int)sfe->namelen,
97                                              (int)sfe->valuelen);
98                         /*
99                          * Either search callback finished early or
100                          * didn't fit it all in the buffer after all.
101                          */
102                         if (context->seen_enough)
103                                 break;
104                         sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
105                 }
106                 trace_xfs_attr_list_sf_all(context);
107                 return 0;
108         }
109
110         /* do no more for a search callback */
111         if (context->bufsize == 0)
112                 return 0;
113
114         /*
115          * It didn't all fit, so we have to sort everything on hashval.
116          */
117         sbsize = sf->hdr.count * sizeof(*sbuf);
118         sbp = sbuf = kmem_alloc(sbsize, KM_NOFS);
119
120         /*
121          * Scan the attribute list for the rest of the entries, storing
122          * the relevant info from only those that match into a buffer.
123          */
124         nsbuf = 0;
125         for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
126                 if (unlikely(
127                     ((char *)sfe < (char *)sf) ||
128                     ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {
129                         XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
130                                              XFS_ERRLEVEL_LOW,
131                                              context->dp->i_mount, sfe,
132                                              sizeof(*sfe));
133                         kmem_free(sbuf);
134                         return -EFSCORRUPTED;
135                 }
136
137                 sbp->entno = i;
138                 sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
139                 sbp->name = sfe->nameval;
140                 sbp->namelen = sfe->namelen;
141                 /* These are bytes, and both on-disk, don't endian-flip */
142                 sbp->valuelen = sfe->valuelen;
143                 sbp->flags = sfe->flags;
144                 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
145                 sbp++;
146                 nsbuf++;
147         }
148
149         /*
150          * Sort the entries on hash then entno.
151          */
152         xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
153
154         /*
155          * Re-find our place IN THE SORTED LIST.
156          */
157         count = 0;
158         cursor->initted = 1;
159         cursor->blkno = 0;
160         for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
161                 if (sbp->hash == cursor->hashval) {
162                         if (cursor->offset == count) {
163                                 break;
164                         }
165                         count++;
166                 } else if (sbp->hash > cursor->hashval) {
167                         break;
168                 }
169         }
170         if (i == nsbuf)
171                 goto out;
172
173         /*
174          * Loop putting entries into the user buffer.
175          */
176         for ( ; i < nsbuf; i++, sbp++) {
177                 if (cursor->hashval != sbp->hash) {
178                         cursor->hashval = sbp->hash;
179                         cursor->offset = 0;
180                 }
181                 if (XFS_IS_CORRUPT(context->dp->i_mount,
182                                    !xfs_attr_namecheck(sbp->name,
183                                                        sbp->namelen))) {
184                         error = -EFSCORRUPTED;
185                         goto out;
186                 }
187                 context->put_listent(context,
188                                      sbp->flags,
189                                      sbp->name,
190                                      sbp->namelen,
191                                      sbp->valuelen);
192                 if (context->seen_enough)
193                         break;
194                 cursor->offset++;
195         }
196 out:
197         kmem_free(sbuf);
198         return error;
199 }
200
201 /*
202  * We didn't find the block & hash mentioned in the cursor state, so
203  * walk down the attr btree looking for the hash.
204  */
205 STATIC int
206 xfs_attr_node_list_lookup(
207         struct xfs_attr_list_context    *context,
208         struct attrlist_cursor_kern     *cursor,
209         struct xfs_buf                  **pbp)
210 {
211         struct xfs_da3_icnode_hdr       nodehdr;
212         struct xfs_da_intnode           *node;
213         struct xfs_da_node_entry        *btree;
214         struct xfs_inode                *dp = context->dp;
215         struct xfs_mount                *mp = dp->i_mount;
216         struct xfs_trans                *tp = context->tp;
217         struct xfs_buf                  *bp;
218         int                             i;
219         int                             error = 0;
220         unsigned int                    expected_level = 0;
221         uint16_t                        magic;
222
223         ASSERT(*pbp == NULL);
224         cursor->blkno = 0;
225         for (;;) {
226                 error = xfs_da3_node_read(tp, dp, cursor->blkno, &bp,
227                                 XFS_ATTR_FORK);
228                 if (error)
229                         return error;
230                 node = bp->b_addr;
231                 magic = be16_to_cpu(node->hdr.info.magic);
232                 if (magic == XFS_ATTR_LEAF_MAGIC ||
233                     magic == XFS_ATTR3_LEAF_MAGIC)
234                         break;
235                 if (magic != XFS_DA_NODE_MAGIC &&
236                     magic != XFS_DA3_NODE_MAGIC) {
237                         XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
238                                         node, sizeof(*node));
239                         goto out_corruptbuf;
240                 }
241
242                 xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
243
244                 /* Tree taller than we can handle; bail out! */
245                 if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
246                         goto out_corruptbuf;
247
248                 /* Check the level from the root node. */
249                 if (cursor->blkno == 0)
250                         expected_level = nodehdr.level - 1;
251                 else if (expected_level != nodehdr.level)
252                         goto out_corruptbuf;
253                 else
254                         expected_level--;
255
256                 btree = nodehdr.btree;
257                 for (i = 0; i < nodehdr.count; btree++, i++) {
258                         if (cursor->hashval <= be32_to_cpu(btree->hashval)) {
259                                 cursor->blkno = be32_to_cpu(btree->before);
260                                 trace_xfs_attr_list_node_descend(context,
261                                                 btree);
262                                 break;
263                         }
264                 }
265                 xfs_trans_brelse(tp, bp);
266
267                 if (i == nodehdr.count)
268                         return 0;
269
270                 /* We can't point back to the root. */
271                 if (XFS_IS_CORRUPT(mp, cursor->blkno == 0))
272                         return -EFSCORRUPTED;
273         }
274
275         if (expected_level != 0)
276                 goto out_corruptbuf;
277
278         *pbp = bp;
279         return 0;
280
281 out_corruptbuf:
282         xfs_buf_corruption_error(bp);
283         xfs_trans_brelse(tp, bp);
284         return -EFSCORRUPTED;
285 }
286
287 STATIC int
288 xfs_attr_node_list(
289         struct xfs_attr_list_context    *context)
290 {
291         struct xfs_attr3_icleaf_hdr     leafhdr;
292         struct attrlist_cursor_kern     *cursor;
293         struct xfs_attr_leafblock       *leaf;
294         struct xfs_da_intnode           *node;
295         struct xfs_buf                  *bp;
296         struct xfs_inode                *dp = context->dp;
297         struct xfs_mount                *mp = dp->i_mount;
298         int                             error = 0;
299
300         trace_xfs_attr_node_list(context);
301
302         cursor = context->cursor;
303         cursor->initted = 1;
304
305         /*
306          * Do all sorts of validation on the passed-in cursor structure.
307          * If anything is amiss, ignore the cursor and look up the hashval
308          * starting from the btree root.
309          */
310         bp = NULL;
311         if (cursor->blkno > 0) {
312                 error = xfs_da3_node_read(context->tp, dp, cursor->blkno, &bp,
313                                 XFS_ATTR_FORK);
314                 if ((error != 0) && (error != -EFSCORRUPTED))
315                         return error;
316                 if (bp) {
317                         struct xfs_attr_leaf_entry *entries;
318
319                         node = bp->b_addr;
320                         switch (be16_to_cpu(node->hdr.info.magic)) {
321                         case XFS_DA_NODE_MAGIC:
322                         case XFS_DA3_NODE_MAGIC:
323                                 trace_xfs_attr_list_wrong_blk(context);
324                                 xfs_trans_brelse(context->tp, bp);
325                                 bp = NULL;
326                                 break;
327                         case XFS_ATTR_LEAF_MAGIC:
328                         case XFS_ATTR3_LEAF_MAGIC:
329                                 leaf = bp->b_addr;
330                                 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
331                                                              &leafhdr, leaf);
332                                 entries = xfs_attr3_leaf_entryp(leaf);
333                                 if (cursor->hashval > be32_to_cpu(
334                                                 entries[leafhdr.count - 1].hashval)) {
335                                         trace_xfs_attr_list_wrong_blk(context);
336                                         xfs_trans_brelse(context->tp, bp);
337                                         bp = NULL;
338                                 } else if (cursor->hashval <= be32_to_cpu(
339                                                 entries[0].hashval)) {
340                                         trace_xfs_attr_list_wrong_blk(context);
341                                         xfs_trans_brelse(context->tp, bp);
342                                         bp = NULL;
343                                 }
344                                 break;
345                         default:
346                                 trace_xfs_attr_list_wrong_blk(context);
347                                 xfs_trans_brelse(context->tp, bp);
348                                 bp = NULL;
349                         }
350                 }
351         }
352
353         /*
354          * We did not find what we expected given the cursor's contents,
355          * so we start from the top and work down based on the hash value.
356          * Note that start of node block is same as start of leaf block.
357          */
358         if (bp == NULL) {
359                 error = xfs_attr_node_list_lookup(context, cursor, &bp);
360                 if (error || !bp)
361                         return error;
362         }
363         ASSERT(bp != NULL);
364
365         /*
366          * Roll upward through the blocks, processing each leaf block in
367          * order.  As long as there is space in the result buffer, keep
368          * adding the information.
369          */
370         for (;;) {
371                 leaf = bp->b_addr;
372                 error = xfs_attr3_leaf_list_int(bp, context);
373                 if (error)
374                         break;
375                 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
376                 if (context->seen_enough || leafhdr.forw == 0)
377                         break;
378                 cursor->blkno = leafhdr.forw;
379                 xfs_trans_brelse(context->tp, bp);
380                 error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
381                                             &bp);
382                 if (error)
383                         return error;
384         }
385         xfs_trans_brelse(context->tp, bp);
386         return error;
387 }
388
389 /*
390  * Copy out attribute list entries for attr_list(), for leaf attribute lists.
391  */
392 int
393 xfs_attr3_leaf_list_int(
394         struct xfs_buf                  *bp,
395         struct xfs_attr_list_context    *context)
396 {
397         struct attrlist_cursor_kern     *cursor;
398         struct xfs_attr_leafblock       *leaf;
399         struct xfs_attr3_icleaf_hdr     ichdr;
400         struct xfs_attr_leaf_entry      *entries;
401         struct xfs_attr_leaf_entry      *entry;
402         int                             i;
403         struct xfs_mount                *mp = context->dp->i_mount;
404
405         trace_xfs_attr_list_leaf(context);
406
407         leaf = bp->b_addr;
408         xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
409         entries = xfs_attr3_leaf_entryp(leaf);
410
411         cursor = context->cursor;
412         cursor->initted = 1;
413
414         /*
415          * Re-find our place in the leaf block if this is a new syscall.
416          */
417         if (context->resynch) {
418                 entry = &entries[0];
419                 for (i = 0; i < ichdr.count; entry++, i++) {
420                         if (be32_to_cpu(entry->hashval) == cursor->hashval) {
421                                 if (cursor->offset == context->dupcnt) {
422                                         context->dupcnt = 0;
423                                         break;
424                                 }
425                                 context->dupcnt++;
426                         } else if (be32_to_cpu(entry->hashval) >
427                                         cursor->hashval) {
428                                 context->dupcnt = 0;
429                                 break;
430                         }
431                 }
432                 if (i == ichdr.count) {
433                         trace_xfs_attr_list_notfound(context);
434                         return 0;
435                 }
436         } else {
437                 entry = &entries[0];
438                 i = 0;
439         }
440         context->resynch = 0;
441
442         /*
443          * We have found our place, start copying out the new attributes.
444          */
445         for (; i < ichdr.count; entry++, i++) {
446                 char *name;
447                 int namelen, valuelen;
448
449                 if (be32_to_cpu(entry->hashval) != cursor->hashval) {
450                         cursor->hashval = be32_to_cpu(entry->hashval);
451                         cursor->offset = 0;
452                 }
453
454                 if ((entry->flags & XFS_ATTR_INCOMPLETE) &&
455                     !context->allow_incomplete)
456                         continue;
457
458                 if (entry->flags & XFS_ATTR_LOCAL) {
459                         xfs_attr_leaf_name_local_t *name_loc;
460
461                         name_loc = xfs_attr3_leaf_name_local(leaf, i);
462                         name = name_loc->nameval;
463                         namelen = name_loc->namelen;
464                         valuelen = be16_to_cpu(name_loc->valuelen);
465                 } else {
466                         xfs_attr_leaf_name_remote_t *name_rmt;
467
468                         name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
469                         name = name_rmt->name;
470                         namelen = name_rmt->namelen;
471                         valuelen = be32_to_cpu(name_rmt->valuelen);
472                 }
473
474                 if (XFS_IS_CORRUPT(context->dp->i_mount,
475                                    !xfs_attr_namecheck(name, namelen)))
476                         return -EFSCORRUPTED;
477                 context->put_listent(context, entry->flags,
478                                               name, namelen, valuelen);
479                 if (context->seen_enough)
480                         break;
481                 cursor->offset++;
482         }
483         trace_xfs_attr_list_leaf_end(context);
484         return 0;
485 }
486
487 /*
488  * Copy out attribute entries for attr_list(), for leaf attribute lists.
489  */
490 STATIC int
491 xfs_attr_leaf_list(
492         struct xfs_attr_list_context    *context)
493 {
494         struct xfs_buf                  *bp;
495         int                             error;
496
497         trace_xfs_attr_leaf_list(context);
498
499         context->cursor->blkno = 0;
500         error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp);
501         if (error)
502                 return error;
503
504         error = xfs_attr3_leaf_list_int(bp, context);
505         xfs_trans_brelse(context->tp, bp);
506         return error;
507 }
508
509 int
510 xfs_attr_list_ilocked(
511         struct xfs_attr_list_context    *context)
512 {
513         struct xfs_inode                *dp = context->dp;
514
515         ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
516
517         /*
518          * Decide on what work routines to call based on the inode size.
519          */
520         if (!xfs_inode_hasattr(dp))
521                 return 0;
522         else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
523                 return xfs_attr_shortform_list(context);
524         else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
525                 return xfs_attr_leaf_list(context);
526         return xfs_attr_node_list(context);
527 }
528
529 int
530 xfs_attr_list(
531         struct xfs_attr_list_context    *context)
532 {
533         struct xfs_inode                *dp = context->dp;
534         uint                            lock_mode;
535         int                             error;
536
537         XFS_STATS_INC(dp->i_mount, xs_attr_list);
538
539         if (XFS_FORCED_SHUTDOWN(dp->i_mount))
540                 return -EIO;
541
542         lock_mode = xfs_ilock_attr_map_shared(dp);
543         error = xfs_attr_list_ilocked(context);
544         xfs_iunlock(dp, lock_mode);
545         return error;
546 }