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