xfs: remove unused header files
[linux-2.6-microblaze.git] / fs / xfs / scrub / attr.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5  */
6 #include "xfs.h"
7 #include "xfs_fs.h"
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_trans_resv.h"
11 #include "xfs_mount.h"
12 #include "xfs_log_format.h"
13 #include "xfs_inode.h"
14 #include "xfs_da_format.h"
15 #include "xfs_da_btree.h"
16 #include "xfs_attr.h"
17 #include "xfs_attr_leaf.h"
18 #include "scrub/scrub.h"
19 #include "scrub/common.h"
20 #include "scrub/dabtree.h"
21
22
23 /* Set us up to scrub an inode's extended attributes. */
24 int
25 xchk_setup_xattr(
26         struct xfs_scrub        *sc,
27         struct xfs_inode        *ip)
28 {
29         size_t                  sz;
30
31         /*
32          * Allocate the buffer without the inode lock held.  We need enough
33          * space to read every xattr value in the file or enough space to
34          * hold three copies of the xattr free space bitmap.  (Not both at
35          * the same time.)
36          */
37         sz = max_t(size_t, XATTR_SIZE_MAX, 3 * sizeof(long) *
38                         BITS_TO_LONGS(sc->mp->m_attr_geo->blksize));
39         sc->buf = kmem_zalloc_large(sz, KM_SLEEP);
40         if (!sc->buf)
41                 return -ENOMEM;
42
43         return xchk_setup_inode_contents(sc, ip, 0);
44 }
45
46 /* Extended Attributes */
47
48 struct xchk_xattr {
49         struct xfs_attr_list_context    context;
50         struct xfs_scrub                *sc;
51 };
52
53 /*
54  * Check that an extended attribute key can be looked up by hash.
55  *
56  * We use the XFS attribute list iterator (i.e. xfs_attr_list_int_ilocked)
57  * to call this function for every attribute key in an inode.  Once
58  * we're here, we load the attribute value to see if any errors happen,
59  * or if we get more or less data than we expected.
60  */
61 static void
62 xchk_xattr_listent(
63         struct xfs_attr_list_context    *context,
64         int                             flags,
65         unsigned char                   *name,
66         int                             namelen,
67         int                             valuelen)
68 {
69         struct xchk_xattr               *sx;
70         struct xfs_da_args              args = { NULL };
71         int                             error = 0;
72
73         sx = container_of(context, struct xchk_xattr, context);
74
75         if (xchk_should_terminate(sx->sc, &error)) {
76                 context->seen_enough = 1;
77                 return;
78         }
79
80         if (flags & XFS_ATTR_INCOMPLETE) {
81                 /* Incomplete attr key, just mark the inode for preening. */
82                 xchk_ino_set_preen(sx->sc, context->dp->i_ino);
83                 return;
84         }
85
86         /* Does this name make sense? */
87         if (!xfs_attr_namecheck(name, namelen)) {
88                 xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno);
89                 return;
90         }
91
92         args.flags = ATTR_KERNOTIME;
93         if (flags & XFS_ATTR_ROOT)
94                 args.flags |= ATTR_ROOT;
95         else if (flags & XFS_ATTR_SECURE)
96                 args.flags |= ATTR_SECURE;
97         args.geo = context->dp->i_mount->m_attr_geo;
98         args.whichfork = XFS_ATTR_FORK;
99         args.dp = context->dp;
100         args.name = name;
101         args.namelen = namelen;
102         args.hashval = xfs_da_hashname(args.name, args.namelen);
103         args.trans = context->tp;
104         args.value = sx->sc->buf;
105         args.valuelen = XATTR_SIZE_MAX;
106
107         error = xfs_attr_get_ilocked(context->dp, &args);
108         if (error == -EEXIST)
109                 error = 0;
110         if (!xchk_fblock_process_error(sx->sc, XFS_ATTR_FORK, args.blkno,
111                         &error))
112                 goto fail_xref;
113         if (args.valuelen != valuelen)
114                 xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK,
115                                              args.blkno);
116 fail_xref:
117         if (sx->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
118                 context->seen_enough = 1;
119         return;
120 }
121
122 /*
123  * Mark a range [start, start+len) in this map.  Returns true if the
124  * region was free, and false if there's a conflict or a problem.
125  *
126  * Within a char, the lowest bit of the char represents the byte with
127  * the smallest address
128  */
129 STATIC bool
130 xchk_xattr_set_map(
131         struct xfs_scrub        *sc,
132         unsigned long           *map,
133         unsigned int            start,
134         unsigned int            len)
135 {
136         unsigned int            mapsize = sc->mp->m_attr_geo->blksize;
137         bool                    ret = true;
138
139         if (start >= mapsize)
140                 return false;
141         if (start + len > mapsize) {
142                 len = mapsize - start;
143                 ret = false;
144         }
145
146         if (find_next_bit(map, mapsize, start) < start + len)
147                 ret = false;
148         bitmap_set(map, start, len);
149
150         return ret;
151 }
152
153 /*
154  * Check the leaf freemap from the usage bitmap.  Returns false if the
155  * attr freemap has problems or points to used space.
156  */
157 STATIC bool
158 xchk_xattr_check_freemap(
159         struct xfs_scrub                *sc,
160         unsigned long                   *map,
161         struct xfs_attr3_icleaf_hdr     *leafhdr)
162 {
163         unsigned long                   *freemap;
164         unsigned long                   *dstmap;
165         unsigned int                    mapsize = sc->mp->m_attr_geo->blksize;
166         int                             i;
167
168         /* Construct bitmap of freemap contents. */
169         freemap = (unsigned long *)sc->buf + BITS_TO_LONGS(mapsize);
170         bitmap_zero(freemap, mapsize);
171         for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
172                 if (!xchk_xattr_set_map(sc, freemap,
173                                 leafhdr->freemap[i].base,
174                                 leafhdr->freemap[i].size))
175                         return false;
176         }
177
178         /* Look for bits that are set in freemap and are marked in use. */
179         dstmap = freemap + BITS_TO_LONGS(mapsize);
180         return bitmap_and(dstmap, freemap, map, mapsize) == 0;
181 }
182
183 /*
184  * Check this leaf entry's relations to everything else.
185  * Returns the number of bytes used for the name/value data.
186  */
187 STATIC void
188 xchk_xattr_entry(
189         struct xchk_da_btree            *ds,
190         int                             level,
191         char                            *buf_end,
192         struct xfs_attr_leafblock       *leaf,
193         struct xfs_attr3_icleaf_hdr     *leafhdr,
194         unsigned long                   *usedmap,
195         struct xfs_attr_leaf_entry      *ent,
196         int                             idx,
197         unsigned int                    *usedbytes,
198         __u32                           *last_hashval)
199 {
200         struct xfs_mount                *mp = ds->state->mp;
201         char                            *name_end;
202         struct xfs_attr_leaf_name_local *lentry;
203         struct xfs_attr_leaf_name_remote *rentry;
204         unsigned int                    nameidx;
205         unsigned int                    namesize;
206
207         if (ent->pad2 != 0)
208                 xchk_da_set_corrupt(ds, level);
209
210         /* Hash values in order? */
211         if (be32_to_cpu(ent->hashval) < *last_hashval)
212                 xchk_da_set_corrupt(ds, level);
213         *last_hashval = be32_to_cpu(ent->hashval);
214
215         nameidx = be16_to_cpu(ent->nameidx);
216         if (nameidx < leafhdr->firstused ||
217             nameidx >= mp->m_attr_geo->blksize) {
218                 xchk_da_set_corrupt(ds, level);
219                 return;
220         }
221
222         /* Check the name information. */
223         if (ent->flags & XFS_ATTR_LOCAL) {
224                 lentry = xfs_attr3_leaf_name_local(leaf, idx);
225                 namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
226                                 be16_to_cpu(lentry->valuelen));
227                 name_end = (char *)lentry + namesize;
228                 if (lentry->namelen == 0)
229                         xchk_da_set_corrupt(ds, level);
230         } else {
231                 rentry = xfs_attr3_leaf_name_remote(leaf, idx);
232                 namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
233                 name_end = (char *)rentry + namesize;
234                 if (rentry->namelen == 0 || rentry->valueblk == 0)
235                         xchk_da_set_corrupt(ds, level);
236         }
237         if (name_end > buf_end)
238                 xchk_da_set_corrupt(ds, level);
239
240         if (!xchk_xattr_set_map(ds->sc, usedmap, nameidx, namesize))
241                 xchk_da_set_corrupt(ds, level);
242         if (!(ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
243                 *usedbytes += namesize;
244 }
245
246 /* Scrub an attribute leaf. */
247 STATIC int
248 xchk_xattr_block(
249         struct xchk_da_btree            *ds,
250         int                             level)
251 {
252         struct xfs_attr3_icleaf_hdr     leafhdr;
253         struct xfs_mount                *mp = ds->state->mp;
254         struct xfs_da_state_blk         *blk = &ds->state->path.blk[level];
255         struct xfs_buf                  *bp = blk->bp;
256         xfs_dablk_t                     *last_checked = ds->private;
257         struct xfs_attr_leafblock       *leaf = bp->b_addr;
258         struct xfs_attr_leaf_entry      *ent;
259         struct xfs_attr_leaf_entry      *entries;
260         unsigned long                   *usedmap = ds->sc->buf;
261         char                            *buf_end;
262         size_t                          off;
263         __u32                           last_hashval = 0;
264         unsigned int                    usedbytes = 0;
265         unsigned int                    hdrsize;
266         int                             i;
267
268         if (*last_checked == blk->blkno)
269                 return 0;
270         *last_checked = blk->blkno;
271         bitmap_zero(usedmap, mp->m_attr_geo->blksize);
272
273         /* Check all the padding. */
274         if (xfs_sb_version_hascrc(&ds->sc->mp->m_sb)) {
275                 struct xfs_attr3_leafblock      *leaf = bp->b_addr;
276
277                 if (leaf->hdr.pad1 != 0 || leaf->hdr.pad2 != 0 ||
278                     leaf->hdr.info.hdr.pad != 0)
279                         xchk_da_set_corrupt(ds, level);
280         } else {
281                 if (leaf->hdr.pad1 != 0 || leaf->hdr.info.pad != 0)
282                         xchk_da_set_corrupt(ds, level);
283         }
284
285         /* Check the leaf header */
286         xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
287         hdrsize = xfs_attr3_leaf_hdr_size(leaf);
288
289         if (leafhdr.usedbytes > mp->m_attr_geo->blksize)
290                 xchk_da_set_corrupt(ds, level);
291         if (leafhdr.firstused > mp->m_attr_geo->blksize)
292                 xchk_da_set_corrupt(ds, level);
293         if (leafhdr.firstused < hdrsize)
294                 xchk_da_set_corrupt(ds, level);
295         if (!xchk_xattr_set_map(ds->sc, usedmap, 0, hdrsize))
296                 xchk_da_set_corrupt(ds, level);
297
298         if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
299                 goto out;
300
301         entries = xfs_attr3_leaf_entryp(leaf);
302         if ((char *)&entries[leafhdr.count] > (char *)leaf + leafhdr.firstused)
303                 xchk_da_set_corrupt(ds, level);
304
305         buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
306         for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {
307                 /* Mark the leaf entry itself. */
308                 off = (char *)ent - (char *)leaf;
309                 if (!xchk_xattr_set_map(ds->sc, usedmap, off,
310                                 sizeof(xfs_attr_leaf_entry_t))) {
311                         xchk_da_set_corrupt(ds, level);
312                         goto out;
313                 }
314
315                 /* Check the entry and nameval. */
316                 xchk_xattr_entry(ds, level, buf_end, leaf, &leafhdr,
317                                 usedmap, ent, i, &usedbytes, &last_hashval);
318
319                 if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
320                         goto out;
321         }
322
323         if (!xchk_xattr_check_freemap(ds->sc, usedmap, &leafhdr))
324                 xchk_da_set_corrupt(ds, level);
325
326         if (leafhdr.usedbytes != usedbytes)
327                 xchk_da_set_corrupt(ds, level);
328
329 out:
330         return 0;
331 }
332
333 /* Scrub a attribute btree record. */
334 STATIC int
335 xchk_xattr_rec(
336         struct xchk_da_btree            *ds,
337         int                             level,
338         void                            *rec)
339 {
340         struct xfs_mount                *mp = ds->state->mp;
341         struct xfs_attr_leaf_entry      *ent = rec;
342         struct xfs_da_state_blk         *blk;
343         struct xfs_attr_leaf_name_local *lentry;
344         struct xfs_attr_leaf_name_remote        *rentry;
345         struct xfs_buf                  *bp;
346         xfs_dahash_t                    calc_hash;
347         xfs_dahash_t                    hash;
348         int                             nameidx;
349         int                             hdrsize;
350         unsigned int                    badflags;
351         int                             error;
352
353         blk = &ds->state->path.blk[level];
354
355         /* Check the whole block, if necessary. */
356         error = xchk_xattr_block(ds, level);
357         if (error)
358                 goto out;
359         if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
360                 goto out;
361
362         /* Check the hash of the entry. */
363         error = xchk_da_btree_hash(ds, level, &ent->hashval);
364         if (error)
365                 goto out;
366
367         /* Find the attr entry's location. */
368         bp = blk->bp;
369         hdrsize = xfs_attr3_leaf_hdr_size(bp->b_addr);
370         nameidx = be16_to_cpu(ent->nameidx);
371         if (nameidx < hdrsize || nameidx >= mp->m_attr_geo->blksize) {
372                 xchk_da_set_corrupt(ds, level);
373                 goto out;
374         }
375
376         /* Retrieve the entry and check it. */
377         hash = be32_to_cpu(ent->hashval);
378         badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE |
379                         XFS_ATTR_INCOMPLETE);
380         if ((ent->flags & badflags) != 0)
381                 xchk_da_set_corrupt(ds, level);
382         if (ent->flags & XFS_ATTR_LOCAL) {
383                 lentry = (struct xfs_attr_leaf_name_local *)
384                                 (((char *)bp->b_addr) + nameidx);
385                 if (lentry->namelen <= 0) {
386                         xchk_da_set_corrupt(ds, level);
387                         goto out;
388                 }
389                 calc_hash = xfs_da_hashname(lentry->nameval, lentry->namelen);
390         } else {
391                 rentry = (struct xfs_attr_leaf_name_remote *)
392                                 (((char *)bp->b_addr) + nameidx);
393                 if (rentry->namelen <= 0) {
394                         xchk_da_set_corrupt(ds, level);
395                         goto out;
396                 }
397                 calc_hash = xfs_da_hashname(rentry->name, rentry->namelen);
398         }
399         if (calc_hash != hash)
400                 xchk_da_set_corrupt(ds, level);
401
402 out:
403         return error;
404 }
405
406 /* Scrub the extended attribute metadata. */
407 int
408 xchk_xattr(
409         struct xfs_scrub                *sc)
410 {
411         struct xchk_xattr               sx;
412         struct attrlist_cursor_kern     cursor = { 0 };
413         xfs_dablk_t                     last_checked = -1U;
414         int                             error = 0;
415
416         if (!xfs_inode_hasattr(sc->ip))
417                 return -ENOENT;
418
419         memset(&sx, 0, sizeof(sx));
420         /* Check attribute tree structure */
421         error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
422                         &last_checked);
423         if (error)
424                 goto out;
425
426         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
427                 goto out;
428
429         /* Check that every attr key can also be looked up by hash. */
430         sx.context.dp = sc->ip;
431         sx.context.cursor = &cursor;
432         sx.context.resynch = 1;
433         sx.context.put_listent = xchk_xattr_listent;
434         sx.context.tp = sc->tp;
435         sx.context.flags = ATTR_INCOMPLETE;
436         sx.sc = sc;
437
438         /*
439          * Look up every xattr in this file by name.
440          *
441          * Use the backend implementation of xfs_attr_list to call
442          * xchk_xattr_listent on every attribute key in this inode.
443          * In other words, we use the same iterator/callback mechanism
444          * that listattr uses to scrub extended attributes, though in our
445          * _listent function, we check the value of the attribute.
446          *
447          * The VFS only locks i_rwsem when modifying attrs, so keep all
448          * three locks held because that's the only way to ensure we're
449          * the only thread poking into the da btree.  We traverse the da
450          * btree while holding a leaf buffer locked for the xattr name
451          * iteration, which doesn't really follow the usual buffer
452          * locking order.
453          */
454         error = xfs_attr_list_int_ilocked(&sx.context);
455         if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, 0, &error))
456                 goto out;
457 out:
458         return error;
459 }