wext: Fix 32 bit iwpriv compatibility issue with 64 bit Kernel
[cascardo/linux.git] / fs / xfs / libxfs / xfs_inode_fork.c
1 /*
2  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include <linux/log2.h>
19
20 #include "xfs.h"
21 #include "xfs_fs.h"
22 #include "xfs_format.h"
23 #include "xfs_log_format.h"
24 #include "xfs_trans_resv.h"
25 #include "xfs_mount.h"
26 #include "xfs_inode.h"
27 #include "xfs_trans.h"
28 #include "xfs_inode_item.h"
29 #include "xfs_bmap_btree.h"
30 #include "xfs_bmap.h"
31 #include "xfs_error.h"
32 #include "xfs_trace.h"
33 #include "xfs_attr_sf.h"
34 #include "xfs_da_format.h"
35
36 kmem_zone_t *xfs_ifork_zone;
37
38 STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int);
39 STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int);
40 STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);
41
42 #ifdef DEBUG
43 /*
44  * Make sure that the extents in the given memory buffer
45  * are valid.
46  */
47 void
48 xfs_validate_extents(
49         xfs_ifork_t             *ifp,
50         int                     nrecs,
51         xfs_exntfmt_t           fmt)
52 {
53         xfs_bmbt_irec_t         irec;
54         xfs_bmbt_rec_host_t     rec;
55         int                     i;
56
57         for (i = 0; i < nrecs; i++) {
58                 xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
59                 rec.l0 = get_unaligned(&ep->l0);
60                 rec.l1 = get_unaligned(&ep->l1);
61                 xfs_bmbt_get_all(&rec, &irec);
62                 if (fmt == XFS_EXTFMT_NOSTATE)
63                         ASSERT(irec.br_state == XFS_EXT_NORM);
64         }
65 }
66 #else /* DEBUG */
67 #define xfs_validate_extents(ifp, nrecs, fmt)
68 #endif /* DEBUG */
69
70
71 /*
72  * Move inode type and inode format specific information from the
73  * on-disk inode to the in-core inode.  For fifos, devs, and sockets
74  * this means set if_rdev to the proper value.  For files, directories,
75  * and symlinks this means to bring in the in-line data or extent
76  * pointers.  For a file in B-tree format, only the root is immediately
77  * brought in-core.  The rest will be in-lined in if_extents when it
78  * is first referenced (see xfs_iread_extents()).
79  */
80 int
81 xfs_iformat_fork(
82         xfs_inode_t             *ip,
83         xfs_dinode_t            *dip)
84 {
85         xfs_attr_shortform_t    *atp;
86         int                     size;
87         int                     error = 0;
88         xfs_fsize_t             di_size;
89
90         if (unlikely(be32_to_cpu(dip->di_nextents) +
91                      be16_to_cpu(dip->di_anextents) >
92                      be64_to_cpu(dip->di_nblocks))) {
93                 xfs_warn(ip->i_mount,
94                         "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.",
95                         (unsigned long long)ip->i_ino,
96                         (int)(be32_to_cpu(dip->di_nextents) +
97                               be16_to_cpu(dip->di_anextents)),
98                         (unsigned long long)
99                                 be64_to_cpu(dip->di_nblocks));
100                 XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW,
101                                      ip->i_mount, dip);
102                 return -EFSCORRUPTED;
103         }
104
105         if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {
106                 xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.",
107                         (unsigned long long)ip->i_ino,
108                         dip->di_forkoff);
109                 XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW,
110                                      ip->i_mount, dip);
111                 return -EFSCORRUPTED;
112         }
113
114         if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) &&
115                      !ip->i_mount->m_rtdev_targp)) {
116                 xfs_warn(ip->i_mount,
117                         "corrupt dinode %Lu, has realtime flag set.",
118                         ip->i_ino);
119                 XFS_CORRUPTION_ERROR("xfs_iformat(realtime)",
120                                      XFS_ERRLEVEL_LOW, ip->i_mount, dip);
121                 return -EFSCORRUPTED;
122         }
123
124         switch (VFS_I(ip)->i_mode & S_IFMT) {
125         case S_IFIFO:
126         case S_IFCHR:
127         case S_IFBLK:
128         case S_IFSOCK:
129                 if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) {
130                         XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW,
131                                               ip->i_mount, dip);
132                         return -EFSCORRUPTED;
133                 }
134                 ip->i_d.di_size = 0;
135                 ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip);
136                 break;
137
138         case S_IFREG:
139         case S_IFLNK:
140         case S_IFDIR:
141                 switch (dip->di_format) {
142                 case XFS_DINODE_FMT_LOCAL:
143                         /*
144                          * no local regular files yet
145                          */
146                         if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) {
147                                 xfs_warn(ip->i_mount,
148                         "corrupt inode %Lu (local format for regular file).",
149                                         (unsigned long long) ip->i_ino);
150                                 XFS_CORRUPTION_ERROR("xfs_iformat(4)",
151                                                      XFS_ERRLEVEL_LOW,
152                                                      ip->i_mount, dip);
153                                 return -EFSCORRUPTED;
154                         }
155
156                         di_size = be64_to_cpu(dip->di_size);
157                         if (unlikely(di_size < 0 ||
158                                      di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) {
159                                 xfs_warn(ip->i_mount,
160                         "corrupt inode %Lu (bad size %Ld for local inode).",
161                                         (unsigned long long) ip->i_ino,
162                                         (long long) di_size);
163                                 XFS_CORRUPTION_ERROR("xfs_iformat(5)",
164                                                      XFS_ERRLEVEL_LOW,
165                                                      ip->i_mount, dip);
166                                 return -EFSCORRUPTED;
167                         }
168
169                         size = (int)di_size;
170                         error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size);
171                         break;
172                 case XFS_DINODE_FMT_EXTENTS:
173                         error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK);
174                         break;
175                 case XFS_DINODE_FMT_BTREE:
176                         error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
177                         break;
178                 default:
179                         XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW,
180                                          ip->i_mount);
181                         return -EFSCORRUPTED;
182                 }
183                 break;
184
185         default:
186                 XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount);
187                 return -EFSCORRUPTED;
188         }
189         if (error) {
190                 return error;
191         }
192         if (!XFS_DFORK_Q(dip))
193                 return 0;
194
195         ASSERT(ip->i_afp == NULL);
196         ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS);
197
198         switch (dip->di_aformat) {
199         case XFS_DINODE_FMT_LOCAL:
200                 atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
201                 size = be16_to_cpu(atp->hdr.totsize);
202
203                 if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) {
204                         xfs_warn(ip->i_mount,
205                                 "corrupt inode %Lu (bad attr fork size %Ld).",
206                                 (unsigned long long) ip->i_ino,
207                                 (long long) size);
208                         XFS_CORRUPTION_ERROR("xfs_iformat(8)",
209                                              XFS_ERRLEVEL_LOW,
210                                              ip->i_mount, dip);
211                         return -EFSCORRUPTED;
212                 }
213
214                 error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
215                 break;
216         case XFS_DINODE_FMT_EXTENTS:
217                 error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK);
218                 break;
219         case XFS_DINODE_FMT_BTREE:
220                 error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK);
221                 break;
222         default:
223                 error = -EFSCORRUPTED;
224                 break;
225         }
226         if (error) {
227                 kmem_zone_free(xfs_ifork_zone, ip->i_afp);
228                 ip->i_afp = NULL;
229                 xfs_idestroy_fork(ip, XFS_DATA_FORK);
230         }
231         return error;
232 }
233
234 /*
235  * The file is in-lined in the on-disk inode.
236  * If it fits into if_inline_data, then copy
237  * it there, otherwise allocate a buffer for it
238  * and copy the data there.  Either way, set
239  * if_data to point at the data.
240  * If we allocate a buffer for the data, make
241  * sure that its size is a multiple of 4 and
242  * record the real size in i_real_bytes.
243  */
244 STATIC int
245 xfs_iformat_local(
246         xfs_inode_t     *ip,
247         xfs_dinode_t    *dip,
248         int             whichfork,
249         int             size)
250 {
251         xfs_ifork_t     *ifp;
252         int             real_size;
253
254         /*
255          * If the size is unreasonable, then something
256          * is wrong and we just bail out rather than crash in
257          * kmem_alloc() or memcpy() below.
258          */
259         if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
260                 xfs_warn(ip->i_mount,
261         "corrupt inode %Lu (bad size %d for local fork, size = %d).",
262                         (unsigned long long) ip->i_ino, size,
263                         XFS_DFORK_SIZE(dip, ip->i_mount, whichfork));
264                 XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW,
265                                      ip->i_mount, dip);
266                 return -EFSCORRUPTED;
267         }
268         ifp = XFS_IFORK_PTR(ip, whichfork);
269         real_size = 0;
270         if (size == 0)
271                 ifp->if_u1.if_data = NULL;
272         else if (size <= sizeof(ifp->if_u2.if_inline_data))
273                 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
274         else {
275                 real_size = roundup(size, 4);
276                 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
277         }
278         ifp->if_bytes = size;
279         ifp->if_real_bytes = real_size;
280         if (size)
281                 memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size);
282         ifp->if_flags &= ~XFS_IFEXTENTS;
283         ifp->if_flags |= XFS_IFINLINE;
284         return 0;
285 }
286
287 /*
288  * The file consists of a set of extents all
289  * of which fit into the on-disk inode.
290  * If there are few enough extents to fit into
291  * the if_inline_ext, then copy them there.
292  * Otherwise allocate a buffer for them and copy
293  * them into it.  Either way, set if_extents
294  * to point at the extents.
295  */
296 STATIC int
297 xfs_iformat_extents(
298         xfs_inode_t     *ip,
299         xfs_dinode_t    *dip,
300         int             whichfork)
301 {
302         xfs_bmbt_rec_t  *dp;
303         xfs_ifork_t     *ifp;
304         int             nex;
305         int             size;
306         int             i;
307
308         ifp = XFS_IFORK_PTR(ip, whichfork);
309         nex = XFS_DFORK_NEXTENTS(dip, whichfork);
310         size = nex * (uint)sizeof(xfs_bmbt_rec_t);
311
312         /*
313          * If the number of extents is unreasonable, then something
314          * is wrong and we just bail out rather than crash in
315          * kmem_alloc() or memcpy() below.
316          */
317         if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
318                 xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).",
319                         (unsigned long long) ip->i_ino, nex);
320                 XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW,
321                                      ip->i_mount, dip);
322                 return -EFSCORRUPTED;
323         }
324
325         ifp->if_real_bytes = 0;
326         if (nex == 0)
327                 ifp->if_u1.if_extents = NULL;
328         else if (nex <= XFS_INLINE_EXTS)
329                 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
330         else
331                 xfs_iext_add(ifp, 0, nex);
332
333         ifp->if_bytes = size;
334         if (size) {
335                 dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);
336                 xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip));
337                 for (i = 0; i < nex; i++, dp++) {
338                         xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
339                         ep->l0 = get_unaligned_be64(&dp->l0);
340                         ep->l1 = get_unaligned_be64(&dp->l1);
341                 }
342                 XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork);
343                 if (whichfork != XFS_DATA_FORK ||
344                         XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE)
345                                 if (unlikely(xfs_check_nostate_extents(
346                                     ifp, 0, nex))) {
347                                         XFS_ERROR_REPORT("xfs_iformat_extents(2)",
348                                                          XFS_ERRLEVEL_LOW,
349                                                          ip->i_mount);
350                                         return -EFSCORRUPTED;
351                                 }
352         }
353         ifp->if_flags |= XFS_IFEXTENTS;
354         return 0;
355 }
356
357 /*
358  * The file has too many extents to fit into
359  * the inode, so they are in B-tree format.
360  * Allocate a buffer for the root of the B-tree
361  * and copy the root into it.  The i_extents
362  * field will remain NULL until all of the
363  * extents are read in (when they are needed).
364  */
365 STATIC int
366 xfs_iformat_btree(
367         xfs_inode_t             *ip,
368         xfs_dinode_t            *dip,
369         int                     whichfork)
370 {
371         struct xfs_mount        *mp = ip->i_mount;
372         xfs_bmdr_block_t        *dfp;
373         xfs_ifork_t             *ifp;
374         /* REFERENCED */
375         int                     nrecs;
376         int                     size;
377
378         ifp = XFS_IFORK_PTR(ip, whichfork);
379         dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
380         size = XFS_BMAP_BROOT_SPACE(mp, dfp);
381         nrecs = be16_to_cpu(dfp->bb_numrecs);
382
383         /*
384          * blow out if -- fork has less extents than can fit in
385          * fork (fork shouldn't be a btree format), root btree
386          * block has more records than can fit into the fork,
387          * or the number of extents is greater than the number of
388          * blocks.
389          */
390         if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <=
391                                         XFS_IFORK_MAXEXT(ip, whichfork) ||
392                      XFS_BMDR_SPACE_CALC(nrecs) >
393                                         XFS_DFORK_SIZE(dip, mp, whichfork) ||
394                      XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
395                 xfs_warn(mp, "corrupt inode %Lu (btree).",
396                                         (unsigned long long) ip->i_ino);
397                 XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
398                                          mp, dip);
399                 return -EFSCORRUPTED;
400         }
401
402         ifp->if_broot_bytes = size;
403         ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS);
404         ASSERT(ifp->if_broot != NULL);
405         /*
406          * Copy and convert from the on-disk structure
407          * to the in-memory structure.
408          */
409         xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
410                          ifp->if_broot, size);
411         ifp->if_flags &= ~XFS_IFEXTENTS;
412         ifp->if_flags |= XFS_IFBROOT;
413
414         return 0;
415 }
416
417 /*
418  * Read in extents from a btree-format inode.
419  * Allocate and fill in if_extents.  Real work is done in xfs_bmap.c.
420  */
421 int
422 xfs_iread_extents(
423         xfs_trans_t     *tp,
424         xfs_inode_t     *ip,
425         int             whichfork)
426 {
427         int             error;
428         xfs_ifork_t     *ifp;
429         xfs_extnum_t    nextents;
430
431         ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
432
433         if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
434                 XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW,
435                                  ip->i_mount);
436                 return -EFSCORRUPTED;
437         }
438         nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
439         ifp = XFS_IFORK_PTR(ip, whichfork);
440
441         /*
442          * We know that the size is valid (it's checked in iformat_btree)
443          */
444         ifp->if_bytes = ifp->if_real_bytes = 0;
445         ifp->if_flags |= XFS_IFEXTENTS;
446         xfs_iext_add(ifp, 0, nextents);
447         error = xfs_bmap_read_extents(tp, ip, whichfork);
448         if (error) {
449                 xfs_iext_destroy(ifp);
450                 ifp->if_flags &= ~XFS_IFEXTENTS;
451                 return error;
452         }
453         xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip));
454         return 0;
455 }
456 /*
457  * Reallocate the space for if_broot based on the number of records
458  * being added or deleted as indicated in rec_diff.  Move the records
459  * and pointers in if_broot to fit the new size.  When shrinking this
460  * will eliminate holes between the records and pointers created by
461  * the caller.  When growing this will create holes to be filled in
462  * by the caller.
463  *
464  * The caller must not request to add more records than would fit in
465  * the on-disk inode root.  If the if_broot is currently NULL, then
466  * if we are adding records, one will be allocated.  The caller must also
467  * not request that the number of records go below zero, although
468  * it can go to zero.
469  *
470  * ip -- the inode whose if_broot area is changing
471  * ext_diff -- the change in the number of records, positive or negative,
472  *       requested for the if_broot array.
473  */
474 void
475 xfs_iroot_realloc(
476         xfs_inode_t             *ip,
477         int                     rec_diff,
478         int                     whichfork)
479 {
480         struct xfs_mount        *mp = ip->i_mount;
481         int                     cur_max;
482         xfs_ifork_t             *ifp;
483         struct xfs_btree_block  *new_broot;
484         int                     new_max;
485         size_t                  new_size;
486         char                    *np;
487         char                    *op;
488
489         /*
490          * Handle the degenerate case quietly.
491          */
492         if (rec_diff == 0) {
493                 return;
494         }
495
496         ifp = XFS_IFORK_PTR(ip, whichfork);
497         if (rec_diff > 0) {
498                 /*
499                  * If there wasn't any memory allocated before, just
500                  * allocate it now and get out.
501                  */
502                 if (ifp->if_broot_bytes == 0) {
503                         new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff);
504                         ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
505                         ifp->if_broot_bytes = (int)new_size;
506                         return;
507                 }
508
509                 /*
510                  * If there is already an existing if_broot, then we need
511                  * to realloc() it and shift the pointers to their new
512                  * location.  The records don't change location because
513                  * they are kept butted up against the btree block header.
514                  */
515                 cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
516                 new_max = cur_max + rec_diff;
517                 new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
518                 ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
519                                 XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max),
520                                 KM_SLEEP | KM_NOFS);
521                 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
522                                                      ifp->if_broot_bytes);
523                 np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
524                                                      (int)new_size);
525                 ifp->if_broot_bytes = (int)new_size;
526                 ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
527                         XFS_IFORK_SIZE(ip, whichfork));
528                 memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t));
529                 return;
530         }
531
532         /*
533          * rec_diff is less than 0.  In this case, we are shrinking the
534          * if_broot buffer.  It must already exist.  If we go to zero
535          * records, just get rid of the root and clear the status bit.
536          */
537         ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0));
538         cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
539         new_max = cur_max + rec_diff;
540         ASSERT(new_max >= 0);
541         if (new_max > 0)
542                 new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
543         else
544                 new_size = 0;
545         if (new_size > 0) {
546                 new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
547                 /*
548                  * First copy over the btree block header.
549                  */
550                 memcpy(new_broot, ifp->if_broot,
551                         XFS_BMBT_BLOCK_LEN(ip->i_mount));
552         } else {
553                 new_broot = NULL;
554                 ifp->if_flags &= ~XFS_IFBROOT;
555         }
556
557         /*
558          * Only copy the records and pointers if there are any.
559          */
560         if (new_max > 0) {
561                 /*
562                  * First copy the records.
563                  */
564                 op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1);
565                 np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1);
566                 memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
567
568                 /*
569                  * Then copy the pointers.
570                  */
571                 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
572                                                      ifp->if_broot_bytes);
573                 np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1,
574                                                      (int)new_size);
575                 memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t));
576         }
577         kmem_free(ifp->if_broot);
578         ifp->if_broot = new_broot;
579         ifp->if_broot_bytes = (int)new_size;
580         if (ifp->if_broot)
581                 ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
582                         XFS_IFORK_SIZE(ip, whichfork));
583         return;
584 }
585
586
587 /*
588  * This is called when the amount of space needed for if_data
589  * is increased or decreased.  The change in size is indicated by
590  * the number of bytes that need to be added or deleted in the
591  * byte_diff parameter.
592  *
593  * If the amount of space needed has decreased below the size of the
594  * inline buffer, then switch to using the inline buffer.  Otherwise,
595  * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer
596  * to what is needed.
597  *
598  * ip -- the inode whose if_data area is changing
599  * byte_diff -- the change in the number of bytes, positive or negative,
600  *       requested for the if_data array.
601  */
602 void
603 xfs_idata_realloc(
604         xfs_inode_t     *ip,
605         int             byte_diff,
606         int             whichfork)
607 {
608         xfs_ifork_t     *ifp;
609         int             new_size;
610         int             real_size;
611
612         if (byte_diff == 0) {
613                 return;
614         }
615
616         ifp = XFS_IFORK_PTR(ip, whichfork);
617         new_size = (int)ifp->if_bytes + byte_diff;
618         ASSERT(new_size >= 0);
619
620         if (new_size == 0) {
621                 if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
622                         kmem_free(ifp->if_u1.if_data);
623                 }
624                 ifp->if_u1.if_data = NULL;
625                 real_size = 0;
626         } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) {
627                 /*
628                  * If the valid extents/data can fit in if_inline_ext/data,
629                  * copy them from the malloc'd vector and free it.
630                  */
631                 if (ifp->if_u1.if_data == NULL) {
632                         ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
633                 } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
634                         ASSERT(ifp->if_real_bytes != 0);
635                         memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
636                               new_size);
637                         kmem_free(ifp->if_u1.if_data);
638                         ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
639                 }
640                 real_size = 0;
641         } else {
642                 /*
643                  * Stuck with malloc/realloc.
644                  * For inline data, the underlying buffer must be
645                  * a multiple of 4 bytes in size so that it can be
646                  * logged and stay on word boundaries.  We enforce
647                  * that here.
648                  */
649                 real_size = roundup(new_size, 4);
650                 if (ifp->if_u1.if_data == NULL) {
651                         ASSERT(ifp->if_real_bytes == 0);
652                         ifp->if_u1.if_data = kmem_alloc(real_size,
653                                                         KM_SLEEP | KM_NOFS);
654                 } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
655                         /*
656                          * Only do the realloc if the underlying size
657                          * is really changing.
658                          */
659                         if (ifp->if_real_bytes != real_size) {
660                                 ifp->if_u1.if_data =
661                                         kmem_realloc(ifp->if_u1.if_data,
662                                                         real_size,
663                                                         ifp->if_real_bytes,
664                                                         KM_SLEEP | KM_NOFS);
665                         }
666                 } else {
667                         ASSERT(ifp->if_real_bytes == 0);
668                         ifp->if_u1.if_data = kmem_alloc(real_size,
669                                                         KM_SLEEP | KM_NOFS);
670                         memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
671                                 ifp->if_bytes);
672                 }
673         }
674         ifp->if_real_bytes = real_size;
675         ifp->if_bytes = new_size;
676         ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
677 }
678
679 void
680 xfs_idestroy_fork(
681         xfs_inode_t     *ip,
682         int             whichfork)
683 {
684         xfs_ifork_t     *ifp;
685
686         ifp = XFS_IFORK_PTR(ip, whichfork);
687         if (ifp->if_broot != NULL) {
688                 kmem_free(ifp->if_broot);
689                 ifp->if_broot = NULL;
690         }
691
692         /*
693          * If the format is local, then we can't have an extents
694          * array so just look for an inline data array.  If we're
695          * not local then we may or may not have an extents list,
696          * so check and free it up if we do.
697          */
698         if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
699                 if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) &&
700                     (ifp->if_u1.if_data != NULL)) {
701                         ASSERT(ifp->if_real_bytes != 0);
702                         kmem_free(ifp->if_u1.if_data);
703                         ifp->if_u1.if_data = NULL;
704                         ifp->if_real_bytes = 0;
705                 }
706         } else if ((ifp->if_flags & XFS_IFEXTENTS) &&
707                    ((ifp->if_flags & XFS_IFEXTIREC) ||
708                     ((ifp->if_u1.if_extents != NULL) &&
709                      (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) {
710                 ASSERT(ifp->if_real_bytes != 0);
711                 xfs_iext_destroy(ifp);
712         }
713         ASSERT(ifp->if_u1.if_extents == NULL ||
714                ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext);
715         ASSERT(ifp->if_real_bytes == 0);
716         if (whichfork == XFS_ATTR_FORK) {
717                 kmem_zone_free(xfs_ifork_zone, ip->i_afp);
718                 ip->i_afp = NULL;
719         }
720 }
721
722 /*
723  * Convert in-core extents to on-disk form
724  *
725  * For either the data or attr fork in extent format, we need to endian convert
726  * the in-core extent as we place them into the on-disk inode.
727  *
728  * In the case of the data fork, the in-core and on-disk fork sizes can be
729  * different due to delayed allocation extents. We only copy on-disk extents
730  * here, so callers must always use the physical fork size to determine the
731  * size of the buffer passed to this routine.  We will return the size actually
732  * used.
733  */
734 int
735 xfs_iextents_copy(
736         xfs_inode_t             *ip,
737         xfs_bmbt_rec_t          *dp,
738         int                     whichfork)
739 {
740         int                     copied;
741         int                     i;
742         xfs_ifork_t             *ifp;
743         int                     nrecs;
744         xfs_fsblock_t           start_block;
745
746         ifp = XFS_IFORK_PTR(ip, whichfork);
747         ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
748         ASSERT(ifp->if_bytes > 0);
749
750         nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
751         XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork);
752         ASSERT(nrecs > 0);
753
754         /*
755          * There are some delayed allocation extents in the
756          * inode, so copy the extents one at a time and skip
757          * the delayed ones.  There must be at least one
758          * non-delayed extent.
759          */
760         copied = 0;
761         for (i = 0; i < nrecs; i++) {
762                 xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
763                 start_block = xfs_bmbt_get_startblock(ep);
764                 if (isnullstartblock(start_block)) {
765                         /*
766                          * It's a delayed allocation extent, so skip it.
767                          */
768                         continue;
769                 }
770
771                 /* Translate to on disk format */
772                 put_unaligned_be64(ep->l0, &dp->l0);
773                 put_unaligned_be64(ep->l1, &dp->l1);
774                 dp++;
775                 copied++;
776         }
777         ASSERT(copied != 0);
778         xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip));
779
780         return (copied * (uint)sizeof(xfs_bmbt_rec_t));
781 }
782
783 /*
784  * Each of the following cases stores data into the same region
785  * of the on-disk inode, so only one of them can be valid at
786  * any given time. While it is possible to have conflicting formats
787  * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is
788  * in EXTENTS format, this can only happen when the fork has
789  * changed formats after being modified but before being flushed.
790  * In these cases, the format always takes precedence, because the
791  * format indicates the current state of the fork.
792  */
793 void
794 xfs_iflush_fork(
795         xfs_inode_t             *ip,
796         xfs_dinode_t            *dip,
797         xfs_inode_log_item_t    *iip,
798         int                     whichfork)
799 {
800         char                    *cp;
801         xfs_ifork_t             *ifp;
802         xfs_mount_t             *mp;
803         static const short      brootflag[2] =
804                 { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT };
805         static const short      dataflag[2] =
806                 { XFS_ILOG_DDATA, XFS_ILOG_ADATA };
807         static const short      extflag[2] =
808                 { XFS_ILOG_DEXT, XFS_ILOG_AEXT };
809
810         if (!iip)
811                 return;
812         ifp = XFS_IFORK_PTR(ip, whichfork);
813         /*
814          * This can happen if we gave up in iformat in an error path,
815          * for the attribute fork.
816          */
817         if (!ifp) {
818                 ASSERT(whichfork == XFS_ATTR_FORK);
819                 return;
820         }
821         cp = XFS_DFORK_PTR(dip, whichfork);
822         mp = ip->i_mount;
823         switch (XFS_IFORK_FORMAT(ip, whichfork)) {
824         case XFS_DINODE_FMT_LOCAL:
825                 if ((iip->ili_fields & dataflag[whichfork]) &&
826                     (ifp->if_bytes > 0)) {
827                         ASSERT(ifp->if_u1.if_data != NULL);
828                         ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
829                         memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes);
830                 }
831                 break;
832
833         case XFS_DINODE_FMT_EXTENTS:
834                 ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
835                        !(iip->ili_fields & extflag[whichfork]));
836                 if ((iip->ili_fields & extflag[whichfork]) &&
837                     (ifp->if_bytes > 0)) {
838                         ASSERT(xfs_iext_get_ext(ifp, 0));
839                         ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
840                         (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,
841                                 whichfork);
842                 }
843                 break;
844
845         case XFS_DINODE_FMT_BTREE:
846                 if ((iip->ili_fields & brootflag[whichfork]) &&
847                     (ifp->if_broot_bytes > 0)) {
848                         ASSERT(ifp->if_broot != NULL);
849                         ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
850                                 XFS_IFORK_SIZE(ip, whichfork));
851                         xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
852                                 (xfs_bmdr_block_t *)cp,
853                                 XFS_DFORK_SIZE(dip, mp, whichfork));
854                 }
855                 break;
856
857         case XFS_DINODE_FMT_DEV:
858                 if (iip->ili_fields & XFS_ILOG_DEV) {
859                         ASSERT(whichfork == XFS_DATA_FORK);
860                         xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev);
861                 }
862                 break;
863
864         case XFS_DINODE_FMT_UUID:
865                 if (iip->ili_fields & XFS_ILOG_UUID) {
866                         ASSERT(whichfork == XFS_DATA_FORK);
867                         memcpy(XFS_DFORK_DPTR(dip),
868                                &ip->i_df.if_u2.if_uuid,
869                                sizeof(uuid_t));
870                 }
871                 break;
872
873         default:
874                 ASSERT(0);
875                 break;
876         }
877 }
878
879 /*
880  * Return a pointer to the extent record at file index idx.
881  */
882 xfs_bmbt_rec_host_t *
883 xfs_iext_get_ext(
884         xfs_ifork_t     *ifp,           /* inode fork pointer */
885         xfs_extnum_t    idx)            /* index of target extent */
886 {
887         ASSERT(idx >= 0);
888         ASSERT(idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
889
890         if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) {
891                 return ifp->if_u1.if_ext_irec->er_extbuf;
892         } else if (ifp->if_flags & XFS_IFEXTIREC) {
893                 xfs_ext_irec_t  *erp;           /* irec pointer */
894                 int             erp_idx = 0;    /* irec index */
895                 xfs_extnum_t    page_idx = idx; /* ext index in target list */
896
897                 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
898                 return &erp->er_extbuf[page_idx];
899         } else if (ifp->if_bytes) {
900                 return &ifp->if_u1.if_extents[idx];
901         } else {
902                 return NULL;
903         }
904 }
905
906 /*
907  * Insert new item(s) into the extent records for incore inode
908  * fork 'ifp'.  'count' new items are inserted at index 'idx'.
909  */
910 void
911 xfs_iext_insert(
912         xfs_inode_t     *ip,            /* incore inode pointer */
913         xfs_extnum_t    idx,            /* starting index of new items */
914         xfs_extnum_t    count,          /* number of inserted items */
915         xfs_bmbt_irec_t *new,           /* items to insert */
916         int             state)          /* type of extent conversion */
917 {
918         xfs_ifork_t     *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
919         xfs_extnum_t    i;              /* extent record index */
920
921         trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_);
922
923         ASSERT(ifp->if_flags & XFS_IFEXTENTS);
924         xfs_iext_add(ifp, idx, count);
925         for (i = idx; i < idx + count; i++, new++)
926                 xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new);
927 }
928
929 /*
930  * This is called when the amount of space required for incore file
931  * extents needs to be increased. The ext_diff parameter stores the
932  * number of new extents being added and the idx parameter contains
933  * the extent index where the new extents will be added. If the new
934  * extents are being appended, then we just need to (re)allocate and
935  * initialize the space. Otherwise, if the new extents are being
936  * inserted into the middle of the existing entries, a bit more work
937  * is required to make room for the new extents to be inserted. The
938  * caller is responsible for filling in the new extent entries upon
939  * return.
940  */
941 void
942 xfs_iext_add(
943         xfs_ifork_t     *ifp,           /* inode fork pointer */
944         xfs_extnum_t    idx,            /* index to begin adding exts */
945         int             ext_diff)       /* number of extents to add */
946 {
947         int             byte_diff;      /* new bytes being added */
948         int             new_size;       /* size of extents after adding */
949         xfs_extnum_t    nextents;       /* number of extents in file */
950
951         nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
952         ASSERT((idx >= 0) && (idx <= nextents));
953         byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t);
954         new_size = ifp->if_bytes + byte_diff;
955         /*
956          * If the new number of extents (nextents + ext_diff)
957          * fits inside the inode, then continue to use the inline
958          * extent buffer.
959          */
960         if (nextents + ext_diff <= XFS_INLINE_EXTS) {
961                 if (idx < nextents) {
962                         memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff],
963                                 &ifp->if_u2.if_inline_ext[idx],
964                                 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
965                         memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff);
966                 }
967                 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
968                 ifp->if_real_bytes = 0;
969         }
970         /*
971          * Otherwise use a linear (direct) extent list.
972          * If the extents are currently inside the inode,
973          * xfs_iext_realloc_direct will switch us from
974          * inline to direct extent allocation mode.
975          */
976         else if (nextents + ext_diff <= XFS_LINEAR_EXTS) {
977                 xfs_iext_realloc_direct(ifp, new_size);
978                 if (idx < nextents) {
979                         memmove(&ifp->if_u1.if_extents[idx + ext_diff],
980                                 &ifp->if_u1.if_extents[idx],
981                                 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
982                         memset(&ifp->if_u1.if_extents[idx], 0, byte_diff);
983                 }
984         }
985         /* Indirection array */
986         else {
987                 xfs_ext_irec_t  *erp;
988                 int             erp_idx = 0;
989                 int             page_idx = idx;
990
991                 ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS);
992                 if (ifp->if_flags & XFS_IFEXTIREC) {
993                         erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1);
994                 } else {
995                         xfs_iext_irec_init(ifp);
996                         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
997                         erp = ifp->if_u1.if_ext_irec;
998                 }
999                 /* Extents fit in target extent page */
1000                 if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) {
1001                         if (page_idx < erp->er_extcount) {
1002                                 memmove(&erp->er_extbuf[page_idx + ext_diff],
1003                                         &erp->er_extbuf[page_idx],
1004                                         (erp->er_extcount - page_idx) *
1005                                         sizeof(xfs_bmbt_rec_t));
1006                                 memset(&erp->er_extbuf[page_idx], 0, byte_diff);
1007                         }
1008                         erp->er_extcount += ext_diff;
1009                         xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
1010                 }
1011                 /* Insert a new extent page */
1012                 else if (erp) {
1013                         xfs_iext_add_indirect_multi(ifp,
1014                                 erp_idx, page_idx, ext_diff);
1015                 }
1016                 /*
1017                  * If extent(s) are being appended to the last page in
1018                  * the indirection array and the new extent(s) don't fit
1019                  * in the page, then erp is NULL and erp_idx is set to
1020                  * the next index needed in the indirection array.
1021                  */
1022                 else {
1023                         uint    count = ext_diff;
1024
1025                         while (count) {
1026                                 erp = xfs_iext_irec_new(ifp, erp_idx);
1027                                 erp->er_extcount = min(count, XFS_LINEAR_EXTS);
1028                                 count -= erp->er_extcount;
1029                                 if (count)
1030                                         erp_idx++;
1031                         }
1032                 }
1033         }
1034         ifp->if_bytes = new_size;
1035 }
1036
1037 /*
1038  * This is called when incore extents are being added to the indirection
1039  * array and the new extents do not fit in the target extent list. The
1040  * erp_idx parameter contains the irec index for the target extent list
1041  * in the indirection array, and the idx parameter contains the extent
1042  * index within the list. The number of extents being added is stored
1043  * in the count parameter.
1044  *
1045  *    |-------|   |-------|
1046  *    |       |   |       |    idx - number of extents before idx
1047  *    |  idx  |   | count |
1048  *    |       |   |       |    count - number of extents being inserted at idx
1049  *    |-------|   |-------|
1050  *    | count |   | nex2  |    nex2 - number of extents after idx + count
1051  *    |-------|   |-------|
1052  */
1053 void
1054 xfs_iext_add_indirect_multi(
1055         xfs_ifork_t     *ifp,                   /* inode fork pointer */
1056         int             erp_idx,                /* target extent irec index */
1057         xfs_extnum_t    idx,                    /* index within target list */
1058         int             count)                  /* new extents being added */
1059 {
1060         int             byte_diff;              /* new bytes being added */
1061         xfs_ext_irec_t  *erp;                   /* pointer to irec entry */
1062         xfs_extnum_t    ext_diff;               /* number of extents to add */
1063         xfs_extnum_t    ext_cnt;                /* new extents still needed */
1064         xfs_extnum_t    nex2;                   /* extents after idx + count */
1065         xfs_bmbt_rec_t  *nex2_ep = NULL;        /* temp list for nex2 extents */
1066         int             nlists;                 /* number of irec's (lists) */
1067
1068         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1069         erp = &ifp->if_u1.if_ext_irec[erp_idx];
1070         nex2 = erp->er_extcount - idx;
1071         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1072
1073         /*
1074          * Save second part of target extent list
1075          * (all extents past */
1076         if (nex2) {
1077                 byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
1078                 nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS);
1079                 memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff);
1080                 erp->er_extcount -= nex2;
1081                 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2);
1082                 memset(&erp->er_extbuf[idx], 0, byte_diff);
1083         }
1084
1085         /*
1086          * Add the new extents to the end of the target
1087          * list, then allocate new irec record(s) and
1088          * extent buffer(s) as needed to store the rest
1089          * of the new extents.
1090          */
1091         ext_cnt = count;
1092         ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount);
1093         if (ext_diff) {
1094                 erp->er_extcount += ext_diff;
1095                 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
1096                 ext_cnt -= ext_diff;
1097         }
1098         while (ext_cnt) {
1099                 erp_idx++;
1100                 erp = xfs_iext_irec_new(ifp, erp_idx);
1101                 ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS);
1102                 erp->er_extcount = ext_diff;
1103                 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
1104                 ext_cnt -= ext_diff;
1105         }
1106
1107         /* Add nex2 extents back to indirection array */
1108         if (nex2) {
1109                 xfs_extnum_t    ext_avail;
1110                 int             i;
1111
1112                 byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
1113                 ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
1114                 i = 0;
1115                 /*
1116                  * If nex2 extents fit in the current page, append
1117                  * nex2_ep after the new extents.
1118                  */
1119                 if (nex2 <= ext_avail) {
1120                         i = erp->er_extcount;
1121                 }
1122                 /*
1123                  * Otherwise, check if space is available in the
1124                  * next page.
1125                  */
1126                 else if ((erp_idx < nlists - 1) &&
1127                          (nex2 <= (ext_avail = XFS_LINEAR_EXTS -
1128                           ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) {
1129                         erp_idx++;
1130                         erp++;
1131                         /* Create a hole for nex2 extents */
1132                         memmove(&erp->er_extbuf[nex2], erp->er_extbuf,
1133                                 erp->er_extcount * sizeof(xfs_bmbt_rec_t));
1134                 }
1135                 /*
1136                  * Final choice, create a new extent page for
1137                  * nex2 extents.
1138                  */
1139                 else {
1140                         erp_idx++;
1141                         erp = xfs_iext_irec_new(ifp, erp_idx);
1142                 }
1143                 memmove(&erp->er_extbuf[i], nex2_ep, byte_diff);
1144                 kmem_free(nex2_ep);
1145                 erp->er_extcount += nex2;
1146                 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2);
1147         }
1148 }
1149
1150 /*
1151  * This is called when the amount of space required for incore file
1152  * extents needs to be decreased. The ext_diff parameter stores the
1153  * number of extents to be removed and the idx parameter contains
1154  * the extent index where the extents will be removed from.
1155  *
1156  * If the amount of space needed has decreased below the linear
1157  * limit, XFS_IEXT_BUFSZ, then switch to using the contiguous
1158  * extent array.  Otherwise, use kmem_realloc() to adjust the
1159  * size to what is needed.
1160  */
1161 void
1162 xfs_iext_remove(
1163         xfs_inode_t     *ip,            /* incore inode pointer */
1164         xfs_extnum_t    idx,            /* index to begin removing exts */
1165         int             ext_diff,       /* number of extents to remove */
1166         int             state)          /* type of extent conversion */
1167 {
1168         xfs_ifork_t     *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
1169         xfs_extnum_t    nextents;       /* number of extents in file */
1170         int             new_size;       /* size of extents after removal */
1171
1172         trace_xfs_iext_remove(ip, idx, state, _RET_IP_);
1173
1174         ASSERT(ext_diff > 0);
1175         nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1176         new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t);
1177
1178         if (new_size == 0) {
1179                 xfs_iext_destroy(ifp);
1180         } else if (ifp->if_flags & XFS_IFEXTIREC) {
1181                 xfs_iext_remove_indirect(ifp, idx, ext_diff);
1182         } else if (ifp->if_real_bytes) {
1183                 xfs_iext_remove_direct(ifp, idx, ext_diff);
1184         } else {
1185                 xfs_iext_remove_inline(ifp, idx, ext_diff);
1186         }
1187         ifp->if_bytes = new_size;
1188 }
1189
1190 /*
1191  * This removes ext_diff extents from the inline buffer, beginning
1192  * at extent index idx.
1193  */
1194 void
1195 xfs_iext_remove_inline(
1196         xfs_ifork_t     *ifp,           /* inode fork pointer */
1197         xfs_extnum_t    idx,            /* index to begin removing exts */
1198         int             ext_diff)       /* number of extents to remove */
1199 {
1200         int             nextents;       /* number of extents in file */
1201
1202         ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
1203         ASSERT(idx < XFS_INLINE_EXTS);
1204         nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1205         ASSERT(((nextents - ext_diff) > 0) &&
1206                 (nextents - ext_diff) < XFS_INLINE_EXTS);
1207
1208         if (idx + ext_diff < nextents) {
1209                 memmove(&ifp->if_u2.if_inline_ext[idx],
1210                         &ifp->if_u2.if_inline_ext[idx + ext_diff],
1211                         (nextents - (idx + ext_diff)) *
1212                          sizeof(xfs_bmbt_rec_t));
1213                 memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff],
1214                         0, ext_diff * sizeof(xfs_bmbt_rec_t));
1215         } else {
1216                 memset(&ifp->if_u2.if_inline_ext[idx], 0,
1217                         ext_diff * sizeof(xfs_bmbt_rec_t));
1218         }
1219 }
1220
1221 /*
1222  * This removes ext_diff extents from a linear (direct) extent list,
1223  * beginning at extent index idx. If the extents are being removed
1224  * from the end of the list (ie. truncate) then we just need to re-
1225  * allocate the list to remove the extra space. Otherwise, if the
1226  * extents are being removed from the middle of the existing extent
1227  * entries, then we first need to move the extent records beginning
1228  * at idx + ext_diff up in the list to overwrite the records being
1229  * removed, then remove the extra space via kmem_realloc.
1230  */
1231 void
1232 xfs_iext_remove_direct(
1233         xfs_ifork_t     *ifp,           /* inode fork pointer */
1234         xfs_extnum_t    idx,            /* index to begin removing exts */
1235         int             ext_diff)       /* number of extents to remove */
1236 {
1237         xfs_extnum_t    nextents;       /* number of extents in file */
1238         int             new_size;       /* size of extents after removal */
1239
1240         ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
1241         new_size = ifp->if_bytes -
1242                 (ext_diff * sizeof(xfs_bmbt_rec_t));
1243         nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1244
1245         if (new_size == 0) {
1246                 xfs_iext_destroy(ifp);
1247                 return;
1248         }
1249         /* Move extents up in the list (if needed) */
1250         if (idx + ext_diff < nextents) {
1251                 memmove(&ifp->if_u1.if_extents[idx],
1252                         &ifp->if_u1.if_extents[idx + ext_diff],
1253                         (nextents - (idx + ext_diff)) *
1254                          sizeof(xfs_bmbt_rec_t));
1255         }
1256         memset(&ifp->if_u1.if_extents[nextents - ext_diff],
1257                 0, ext_diff * sizeof(xfs_bmbt_rec_t));
1258         /*
1259          * Reallocate the direct extent list. If the extents
1260          * will fit inside the inode then xfs_iext_realloc_direct
1261          * will switch from direct to inline extent allocation
1262          * mode for us.
1263          */
1264         xfs_iext_realloc_direct(ifp, new_size);
1265         ifp->if_bytes = new_size;
1266 }
1267
1268 /*
1269  * This is called when incore extents are being removed from the
1270  * indirection array and the extents being removed span multiple extent
1271  * buffers. The idx parameter contains the file extent index where we
1272  * want to begin removing extents, and the count parameter contains
1273  * how many extents need to be removed.
1274  *
1275  *    |-------|   |-------|
1276  *    | nex1  |   |       |    nex1 - number of extents before idx
1277  *    |-------|   | count |
1278  *    |       |   |       |    count - number of extents being removed at idx
1279  *    | count |   |-------|
1280  *    |       |   | nex2  |    nex2 - number of extents after idx + count
1281  *    |-------|   |-------|
1282  */
1283 void
1284 xfs_iext_remove_indirect(
1285         xfs_ifork_t     *ifp,           /* inode fork pointer */
1286         xfs_extnum_t    idx,            /* index to begin removing extents */
1287         int             count)          /* number of extents to remove */
1288 {
1289         xfs_ext_irec_t  *erp;           /* indirection array pointer */
1290         int             erp_idx = 0;    /* indirection array index */
1291         xfs_extnum_t    ext_cnt;        /* extents left to remove */
1292         xfs_extnum_t    ext_diff;       /* extents to remove in current list */
1293         xfs_extnum_t    nex1;           /* number of extents before idx */
1294         xfs_extnum_t    nex2;           /* extents after idx + count */
1295         int             page_idx = idx; /* index in target extent list */
1296
1297         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1298         erp = xfs_iext_idx_to_irec(ifp,  &page_idx, &erp_idx, 0);
1299         ASSERT(erp != NULL);
1300         nex1 = page_idx;
1301         ext_cnt = count;
1302         while (ext_cnt) {
1303                 nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0);
1304                 ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1));
1305                 /*
1306                  * Check for deletion of entire list;
1307                  * xfs_iext_irec_remove() updates extent offsets.
1308                  */
1309                 if (ext_diff == erp->er_extcount) {
1310                         xfs_iext_irec_remove(ifp, erp_idx);
1311                         ext_cnt -= ext_diff;
1312                         nex1 = 0;
1313                         if (ext_cnt) {
1314                                 ASSERT(erp_idx < ifp->if_real_bytes /
1315                                         XFS_IEXT_BUFSZ);
1316                                 erp = &ifp->if_u1.if_ext_irec[erp_idx];
1317                                 nex1 = 0;
1318                                 continue;
1319                         } else {
1320                                 break;
1321                         }
1322                 }
1323                 /* Move extents up (if needed) */
1324                 if (nex2) {
1325                         memmove(&erp->er_extbuf[nex1],
1326                                 &erp->er_extbuf[nex1 + ext_diff],
1327                                 nex2 * sizeof(xfs_bmbt_rec_t));
1328                 }
1329                 /* Zero out rest of page */
1330                 memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ -
1331                         ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t))));
1332                 /* Update remaining counters */
1333                 erp->er_extcount -= ext_diff;
1334                 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff);
1335                 ext_cnt -= ext_diff;
1336                 nex1 = 0;
1337                 erp_idx++;
1338                 erp++;
1339         }
1340         ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t);
1341         xfs_iext_irec_compact(ifp);
1342 }
1343
1344 /*
1345  * Create, destroy, or resize a linear (direct) block of extents.
1346  */
1347 void
1348 xfs_iext_realloc_direct(
1349         xfs_ifork_t     *ifp,           /* inode fork pointer */
1350         int             new_size)       /* new size of extents after adding */
1351 {
1352         int             rnew_size;      /* real new size of extents */
1353
1354         rnew_size = new_size;
1355
1356         ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) ||
1357                 ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) &&
1358                  (new_size != ifp->if_real_bytes)));
1359
1360         /* Free extent records */
1361         if (new_size == 0) {
1362                 xfs_iext_destroy(ifp);
1363         }
1364         /* Resize direct extent list and zero any new bytes */
1365         else if (ifp->if_real_bytes) {
1366                 /* Check if extents will fit inside the inode */
1367                 if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) {
1368                         xfs_iext_direct_to_inline(ifp, new_size /
1369                                 (uint)sizeof(xfs_bmbt_rec_t));
1370                         ifp->if_bytes = new_size;
1371                         return;
1372                 }
1373                 if (!is_power_of_2(new_size)){
1374                         rnew_size = roundup_pow_of_two(new_size);
1375                 }
1376                 if (rnew_size != ifp->if_real_bytes) {
1377                         ifp->if_u1.if_extents =
1378                                 kmem_realloc(ifp->if_u1.if_extents,
1379                                                 rnew_size,
1380                                                 ifp->if_real_bytes, KM_NOFS);
1381                 }
1382                 if (rnew_size > ifp->if_real_bytes) {
1383                         memset(&ifp->if_u1.if_extents[ifp->if_bytes /
1384                                 (uint)sizeof(xfs_bmbt_rec_t)], 0,
1385                                 rnew_size - ifp->if_real_bytes);
1386                 }
1387         }
1388         /* Switch from the inline extent buffer to a direct extent list */
1389         else {
1390                 if (!is_power_of_2(new_size)) {
1391                         rnew_size = roundup_pow_of_two(new_size);
1392                 }
1393                 xfs_iext_inline_to_direct(ifp, rnew_size);
1394         }
1395         ifp->if_real_bytes = rnew_size;
1396         ifp->if_bytes = new_size;
1397 }
1398
1399 /*
1400  * Switch from linear (direct) extent records to inline buffer.
1401  */
1402 void
1403 xfs_iext_direct_to_inline(
1404         xfs_ifork_t     *ifp,           /* inode fork pointer */
1405         xfs_extnum_t    nextents)       /* number of extents in file */
1406 {
1407         ASSERT(ifp->if_flags & XFS_IFEXTENTS);
1408         ASSERT(nextents <= XFS_INLINE_EXTS);
1409         /*
1410          * The inline buffer was zeroed when we switched
1411          * from inline to direct extent allocation mode,
1412          * so we don't need to clear it here.
1413          */
1414         memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
1415                 nextents * sizeof(xfs_bmbt_rec_t));
1416         kmem_free(ifp->if_u1.if_extents);
1417         ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
1418         ifp->if_real_bytes = 0;
1419 }
1420
1421 /*
1422  * Switch from inline buffer to linear (direct) extent records.
1423  * new_size should already be rounded up to the next power of 2
1424  * by the caller (when appropriate), so use new_size as it is.
1425  * However, since new_size may be rounded up, we can't update
1426  * if_bytes here. It is the caller's responsibility to update
1427  * if_bytes upon return.
1428  */
1429 void
1430 xfs_iext_inline_to_direct(
1431         xfs_ifork_t     *ifp,           /* inode fork pointer */
1432         int             new_size)       /* number of extents in file */
1433 {
1434         ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS);
1435         memset(ifp->if_u1.if_extents, 0, new_size);
1436         if (ifp->if_bytes) {
1437                 memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
1438                         ifp->if_bytes);
1439                 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
1440                         sizeof(xfs_bmbt_rec_t));
1441         }
1442         ifp->if_real_bytes = new_size;
1443 }
1444
1445 /*
1446  * Resize an extent indirection array to new_size bytes.
1447  */
1448 STATIC void
1449 xfs_iext_realloc_indirect(
1450         xfs_ifork_t     *ifp,           /* inode fork pointer */
1451         int             new_size)       /* new indirection array size */
1452 {
1453         int             nlists;         /* number of irec's (ex lists) */
1454         int             size;           /* current indirection array size */
1455
1456         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1457         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1458         size = nlists * sizeof(xfs_ext_irec_t);
1459         ASSERT(ifp->if_real_bytes);
1460         ASSERT((new_size >= 0) && (new_size != size));
1461         if (new_size == 0) {
1462                 xfs_iext_destroy(ifp);
1463         } else {
1464                 ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *)
1465                         kmem_realloc(ifp->if_u1.if_ext_irec,
1466                                 new_size, size, KM_NOFS);
1467         }
1468 }
1469
1470 /*
1471  * Switch from indirection array to linear (direct) extent allocations.
1472  */
1473 STATIC void
1474 xfs_iext_indirect_to_direct(
1475          xfs_ifork_t    *ifp)           /* inode fork pointer */
1476 {
1477         xfs_bmbt_rec_host_t *ep;        /* extent record pointer */
1478         xfs_extnum_t    nextents;       /* number of extents in file */
1479         int             size;           /* size of file extents */
1480
1481         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1482         nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1483         ASSERT(nextents <= XFS_LINEAR_EXTS);
1484         size = nextents * sizeof(xfs_bmbt_rec_t);
1485
1486         xfs_iext_irec_compact_pages(ifp);
1487         ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ);
1488
1489         ep = ifp->if_u1.if_ext_irec->er_extbuf;
1490         kmem_free(ifp->if_u1.if_ext_irec);
1491         ifp->if_flags &= ~XFS_IFEXTIREC;
1492         ifp->if_u1.if_extents = ep;
1493         ifp->if_bytes = size;
1494         if (nextents < XFS_LINEAR_EXTS) {
1495                 xfs_iext_realloc_direct(ifp, size);
1496         }
1497 }
1498
1499 /*
1500  * Free incore file extents.
1501  */
1502 void
1503 xfs_iext_destroy(
1504         xfs_ifork_t     *ifp)           /* inode fork pointer */
1505 {
1506         if (ifp->if_flags & XFS_IFEXTIREC) {
1507                 int     erp_idx;
1508                 int     nlists;
1509
1510                 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1511                 for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) {
1512                         xfs_iext_irec_remove(ifp, erp_idx);
1513                 }
1514                 ifp->if_flags &= ~XFS_IFEXTIREC;
1515         } else if (ifp->if_real_bytes) {
1516                 kmem_free(ifp->if_u1.if_extents);
1517         } else if (ifp->if_bytes) {
1518                 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
1519                         sizeof(xfs_bmbt_rec_t));
1520         }
1521         ifp->if_u1.if_extents = NULL;
1522         ifp->if_real_bytes = 0;
1523         ifp->if_bytes = 0;
1524 }
1525
1526 /*
1527  * Return a pointer to the extent record for file system block bno.
1528  */
1529 xfs_bmbt_rec_host_t *                   /* pointer to found extent record */
1530 xfs_iext_bno_to_ext(
1531         xfs_ifork_t     *ifp,           /* inode fork pointer */
1532         xfs_fileoff_t   bno,            /* block number to search for */
1533         xfs_extnum_t    *idxp)          /* index of target extent */
1534 {
1535         xfs_bmbt_rec_host_t *base;      /* pointer to first extent */
1536         xfs_filblks_t   blockcount = 0; /* number of blocks in extent */
1537         xfs_bmbt_rec_host_t *ep = NULL; /* pointer to target extent */
1538         xfs_ext_irec_t  *erp = NULL;    /* indirection array pointer */
1539         int             high;           /* upper boundary in search */
1540         xfs_extnum_t    idx = 0;        /* index of target extent */
1541         int             low;            /* lower boundary in search */
1542         xfs_extnum_t    nextents;       /* number of file extents */
1543         xfs_fileoff_t   startoff = 0;   /* start offset of extent */
1544
1545         nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1546         if (nextents == 0) {
1547                 *idxp = 0;
1548                 return NULL;
1549         }
1550         low = 0;
1551         if (ifp->if_flags & XFS_IFEXTIREC) {
1552                 /* Find target extent list */
1553                 int     erp_idx = 0;
1554                 erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx);
1555                 base = erp->er_extbuf;
1556                 high = erp->er_extcount - 1;
1557         } else {
1558                 base = ifp->if_u1.if_extents;
1559                 high = nextents - 1;
1560         }
1561         /* Binary search extent records */
1562         while (low <= high) {
1563                 idx = (low + high) >> 1;
1564                 ep = base + idx;
1565                 startoff = xfs_bmbt_get_startoff(ep);
1566                 blockcount = xfs_bmbt_get_blockcount(ep);
1567                 if (bno < startoff) {
1568                         high = idx - 1;
1569                 } else if (bno >= startoff + blockcount) {
1570                         low = idx + 1;
1571                 } else {
1572                         /* Convert back to file-based extent index */
1573                         if (ifp->if_flags & XFS_IFEXTIREC) {
1574                                 idx += erp->er_extoff;
1575                         }
1576                         *idxp = idx;
1577                         return ep;
1578                 }
1579         }
1580         /* Convert back to file-based extent index */
1581         if (ifp->if_flags & XFS_IFEXTIREC) {
1582                 idx += erp->er_extoff;
1583         }
1584         if (bno >= startoff + blockcount) {
1585                 if (++idx == nextents) {
1586                         ep = NULL;
1587                 } else {
1588                         ep = xfs_iext_get_ext(ifp, idx);
1589                 }
1590         }
1591         *idxp = idx;
1592         return ep;
1593 }
1594
1595 /*
1596  * Return a pointer to the indirection array entry containing the
1597  * extent record for filesystem block bno. Store the index of the
1598  * target irec in *erp_idxp.
1599  */
1600 xfs_ext_irec_t *                        /* pointer to found extent record */
1601 xfs_iext_bno_to_irec(
1602         xfs_ifork_t     *ifp,           /* inode fork pointer */
1603         xfs_fileoff_t   bno,            /* block number to search for */
1604         int             *erp_idxp)      /* irec index of target ext list */
1605 {
1606         xfs_ext_irec_t  *erp = NULL;    /* indirection array pointer */
1607         xfs_ext_irec_t  *erp_next;      /* next indirection array entry */
1608         int             erp_idx;        /* indirection array index */
1609         int             nlists;         /* number of extent irec's (lists) */
1610         int             high;           /* binary search upper limit */
1611         int             low;            /* binary search lower limit */
1612
1613         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1614         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1615         erp_idx = 0;
1616         low = 0;
1617         high = nlists - 1;
1618         while (low <= high) {
1619                 erp_idx = (low + high) >> 1;
1620                 erp = &ifp->if_u1.if_ext_irec[erp_idx];
1621                 erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL;
1622                 if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) {
1623                         high = erp_idx - 1;
1624                 } else if (erp_next && bno >=
1625                            xfs_bmbt_get_startoff(erp_next->er_extbuf)) {
1626                         low = erp_idx + 1;
1627                 } else {
1628                         break;
1629                 }
1630         }
1631         *erp_idxp = erp_idx;
1632         return erp;
1633 }
1634
1635 /*
1636  * Return a pointer to the indirection array entry containing the
1637  * extent record at file extent index *idxp. Store the index of the
1638  * target irec in *erp_idxp and store the page index of the target
1639  * extent record in *idxp.
1640  */
1641 xfs_ext_irec_t *
1642 xfs_iext_idx_to_irec(
1643         xfs_ifork_t     *ifp,           /* inode fork pointer */
1644         xfs_extnum_t    *idxp,          /* extent index (file -> page) */
1645         int             *erp_idxp,      /* pointer to target irec */
1646         int             realloc)        /* new bytes were just added */
1647 {
1648         xfs_ext_irec_t  *prev;          /* pointer to previous irec */
1649         xfs_ext_irec_t  *erp = NULL;    /* pointer to current irec */
1650         int             erp_idx;        /* indirection array index */
1651         int             nlists;         /* number of irec's (ex lists) */
1652         int             high;           /* binary search upper limit */
1653         int             low;            /* binary search lower limit */
1654         xfs_extnum_t    page_idx = *idxp; /* extent index in target list */
1655
1656         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1657         ASSERT(page_idx >= 0);
1658         ASSERT(page_idx <= ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
1659         ASSERT(page_idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t) || realloc);
1660
1661         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1662         erp_idx = 0;
1663         low = 0;
1664         high = nlists - 1;
1665
1666         /* Binary search extent irec's */
1667         while (low <= high) {
1668                 erp_idx = (low + high) >> 1;
1669                 erp = &ifp->if_u1.if_ext_irec[erp_idx];
1670                 prev = erp_idx > 0 ? erp - 1 : NULL;
1671                 if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff &&
1672                      realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) {
1673                         high = erp_idx - 1;
1674                 } else if (page_idx > erp->er_extoff + erp->er_extcount ||
1675                            (page_idx == erp->er_extoff + erp->er_extcount &&
1676                             !realloc)) {
1677                         low = erp_idx + 1;
1678                 } else if (page_idx == erp->er_extoff + erp->er_extcount &&
1679                            erp->er_extcount == XFS_LINEAR_EXTS) {
1680                         ASSERT(realloc);
1681                         page_idx = 0;
1682                         erp_idx++;
1683                         erp = erp_idx < nlists ? erp + 1 : NULL;
1684                         break;
1685                 } else {
1686                         page_idx -= erp->er_extoff;
1687                         break;
1688                 }
1689         }
1690         *idxp = page_idx;
1691         *erp_idxp = erp_idx;
1692         return erp;
1693 }
1694
1695 /*
1696  * Allocate and initialize an indirection array once the space needed
1697  * for incore extents increases above XFS_IEXT_BUFSZ.
1698  */
1699 void
1700 xfs_iext_irec_init(
1701         xfs_ifork_t     *ifp)           /* inode fork pointer */
1702 {
1703         xfs_ext_irec_t  *erp;           /* indirection array pointer */
1704         xfs_extnum_t    nextents;       /* number of extents in file */
1705
1706         ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
1707         nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1708         ASSERT(nextents <= XFS_LINEAR_EXTS);
1709
1710         erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS);
1711
1712         if (nextents == 0) {
1713                 ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
1714         } else if (!ifp->if_real_bytes) {
1715                 xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ);
1716         } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) {
1717                 xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ);
1718         }
1719         erp->er_extbuf = ifp->if_u1.if_extents;
1720         erp->er_extcount = nextents;
1721         erp->er_extoff = 0;
1722
1723         ifp->if_flags |= XFS_IFEXTIREC;
1724         ifp->if_real_bytes = XFS_IEXT_BUFSZ;
1725         ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t);
1726         ifp->if_u1.if_ext_irec = erp;
1727
1728         return;
1729 }
1730
1731 /*
1732  * Allocate and initialize a new entry in the indirection array.
1733  */
1734 xfs_ext_irec_t *
1735 xfs_iext_irec_new(
1736         xfs_ifork_t     *ifp,           /* inode fork pointer */
1737         int             erp_idx)        /* index for new irec */
1738 {
1739         xfs_ext_irec_t  *erp;           /* indirection array pointer */
1740         int             i;              /* loop counter */
1741         int             nlists;         /* number of irec's (ex lists) */
1742
1743         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1744         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1745
1746         /* Resize indirection array */
1747         xfs_iext_realloc_indirect(ifp, ++nlists *
1748                                   sizeof(xfs_ext_irec_t));
1749         /*
1750          * Move records down in the array so the
1751          * new page can use erp_idx.
1752          */
1753         erp = ifp->if_u1.if_ext_irec;
1754         for (i = nlists - 1; i > erp_idx; i--) {
1755                 memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t));
1756         }
1757         ASSERT(i == erp_idx);
1758
1759         /* Initialize new extent record */
1760         erp = ifp->if_u1.if_ext_irec;
1761         erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
1762         ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
1763         memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ);
1764         erp[erp_idx].er_extcount = 0;
1765         erp[erp_idx].er_extoff = erp_idx > 0 ?
1766                 erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0;
1767         return (&erp[erp_idx]);
1768 }
1769
1770 /*
1771  * Remove a record from the indirection array.
1772  */
1773 void
1774 xfs_iext_irec_remove(
1775         xfs_ifork_t     *ifp,           /* inode fork pointer */
1776         int             erp_idx)        /* irec index to remove */
1777 {
1778         xfs_ext_irec_t  *erp;           /* indirection array pointer */
1779         int             i;              /* loop counter */
1780         int             nlists;         /* number of irec's (ex lists) */
1781
1782         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1783         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1784         erp = &ifp->if_u1.if_ext_irec[erp_idx];
1785         if (erp->er_extbuf) {
1786                 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1,
1787                         -erp->er_extcount);
1788                 kmem_free(erp->er_extbuf);
1789         }
1790         /* Compact extent records */
1791         erp = ifp->if_u1.if_ext_irec;
1792         for (i = erp_idx; i < nlists - 1; i++) {
1793                 memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t));
1794         }
1795         /*
1796          * Manually free the last extent record from the indirection
1797          * array.  A call to xfs_iext_realloc_indirect() with a size
1798          * of zero would result in a call to xfs_iext_destroy() which
1799          * would in turn call this function again, creating a nasty
1800          * infinite loop.
1801          */
1802         if (--nlists) {
1803                 xfs_iext_realloc_indirect(ifp,
1804                         nlists * sizeof(xfs_ext_irec_t));
1805         } else {
1806                 kmem_free(ifp->if_u1.if_ext_irec);
1807         }
1808         ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
1809 }
1810
1811 /*
1812  * This is called to clean up large amounts of unused memory allocated
1813  * by the indirection array.  Before compacting anything though, verify
1814  * that the indirection array is still needed and switch back to the
1815  * linear extent list (or even the inline buffer) if possible.  The
1816  * compaction policy is as follows:
1817  *
1818  *    Full Compaction: Extents fit into a single page (or inline buffer)
1819  * Partial Compaction: Extents occupy less than 50% of allocated space
1820  *      No Compaction: Extents occupy at least 50% of allocated space
1821  */
1822 void
1823 xfs_iext_irec_compact(
1824         xfs_ifork_t     *ifp)           /* inode fork pointer */
1825 {
1826         xfs_extnum_t    nextents;       /* number of extents in file */
1827         int             nlists;         /* number of irec's (ex lists) */
1828
1829         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1830         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1831         nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1832
1833         if (nextents == 0) {
1834                 xfs_iext_destroy(ifp);
1835         } else if (nextents <= XFS_INLINE_EXTS) {
1836                 xfs_iext_indirect_to_direct(ifp);
1837                 xfs_iext_direct_to_inline(ifp, nextents);
1838         } else if (nextents <= XFS_LINEAR_EXTS) {
1839                 xfs_iext_indirect_to_direct(ifp);
1840         } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) {
1841                 xfs_iext_irec_compact_pages(ifp);
1842         }
1843 }
1844
1845 /*
1846  * Combine extents from neighboring extent pages.
1847  */
1848 void
1849 xfs_iext_irec_compact_pages(
1850         xfs_ifork_t     *ifp)           /* inode fork pointer */
1851 {
1852         xfs_ext_irec_t  *erp, *erp_next;/* pointers to irec entries */
1853         int             erp_idx = 0;    /* indirection array index */
1854         int             nlists;         /* number of irec's (ex lists) */
1855
1856         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1857         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1858         while (erp_idx < nlists - 1) {
1859                 erp = &ifp->if_u1.if_ext_irec[erp_idx];
1860                 erp_next = erp + 1;
1861                 if (erp_next->er_extcount <=
1862                     (XFS_LINEAR_EXTS - erp->er_extcount)) {
1863                         memcpy(&erp->er_extbuf[erp->er_extcount],
1864                                 erp_next->er_extbuf, erp_next->er_extcount *
1865                                 sizeof(xfs_bmbt_rec_t));
1866                         erp->er_extcount += erp_next->er_extcount;
1867                         /*
1868                          * Free page before removing extent record
1869                          * so er_extoffs don't get modified in
1870                          * xfs_iext_irec_remove.
1871                          */
1872                         kmem_free(erp_next->er_extbuf);
1873                         erp_next->er_extbuf = NULL;
1874                         xfs_iext_irec_remove(ifp, erp_idx + 1);
1875                         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1876                 } else {
1877                         erp_idx++;
1878                 }
1879         }
1880 }
1881
1882 /*
1883  * This is called to update the er_extoff field in the indirection
1884  * array when extents have been added or removed from one of the
1885  * extent lists. erp_idx contains the irec index to begin updating
1886  * at and ext_diff contains the number of extents that were added
1887  * or removed.
1888  */
1889 void
1890 xfs_iext_irec_update_extoffs(
1891         xfs_ifork_t     *ifp,           /* inode fork pointer */
1892         int             erp_idx,        /* irec index to update */
1893         int             ext_diff)       /* number of new extents */
1894 {
1895         int             i;              /* loop counter */
1896         int             nlists;         /* number of irec's (ex lists */
1897
1898         ASSERT(ifp->if_flags & XFS_IFEXTIREC);
1899         nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
1900         for (i = erp_idx; i < nlists; i++) {
1901                 ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff;
1902         }
1903 }