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