Use boot based time for uptime in /proc
[linux-2.6] / fs / xfs / xfs_dir2_sf.c
1 /*
2  * Copyright (c) 2000-2003,2005 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 "xfs.h"
19 #include "xfs_fs.h"
20 #include "xfs_types.h"
21 #include "xfs_log.h"
22 #include "xfs_inum.h"
23 #include "xfs_trans.h"
24 #include "xfs_sb.h"
25 #include "xfs_dir2.h"
26 #include "xfs_dmapi.h"
27 #include "xfs_mount.h"
28 #include "xfs_da_btree.h"
29 #include "xfs_bmap_btree.h"
30 #include "xfs_dir2_sf.h"
31 #include "xfs_attr_sf.h"
32 #include "xfs_dinode.h"
33 #include "xfs_inode.h"
34 #include "xfs_inode_item.h"
35 #include "xfs_error.h"
36 #include "xfs_dir2_data.h"
37 #include "xfs_dir2_leaf.h"
38 #include "xfs_dir2_block.h"
39 #include "xfs_dir2_trace.h"
40
41 /*
42  * Prototypes for internal functions.
43  */
44 static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args,
45                                      xfs_dir2_sf_entry_t *sfep,
46                                      xfs_dir2_data_aoff_t offset,
47                                      int new_isize);
48 static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange,
49                                      int new_isize);
50 static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange,
51                                     xfs_dir2_sf_entry_t **sfepp,
52                                     xfs_dir2_data_aoff_t *offsetp);
53 #ifdef DEBUG
54 static void xfs_dir2_sf_check(xfs_da_args_t *args);
55 #else
56 #define xfs_dir2_sf_check(args)
57 #endif /* DEBUG */
58 #if XFS_BIG_INUMS
59 static void xfs_dir2_sf_toino4(xfs_da_args_t *args);
60 static void xfs_dir2_sf_toino8(xfs_da_args_t *args);
61 #endif /* XFS_BIG_INUMS */
62
63 /*
64  * Given a block directory (dp/block), calculate its size as a shortform (sf)
65  * directory and a header for the sf directory, if it will fit it the
66  * space currently present in the inode.  If it won't fit, the output
67  * size is too big (but not accurate).
68  */
69 int                                             /* size for sf form */
70 xfs_dir2_block_sfsize(
71         xfs_inode_t             *dp,            /* incore inode pointer */
72         xfs_dir2_block_t        *block,         /* block directory data */
73         xfs_dir2_sf_hdr_t       *sfhp)          /* output: header for sf form */
74 {
75         xfs_dir2_dataptr_t      addr;           /* data entry address */
76         xfs_dir2_leaf_entry_t   *blp;           /* leaf area of the block */
77         xfs_dir2_block_tail_t   *btp;           /* tail area of the block */
78         int                     count;          /* shortform entry count */
79         xfs_dir2_data_entry_t   *dep;           /* data entry in the block */
80         int                     i;              /* block entry index */
81         int                     i8count;        /* count of big-inode entries */
82         int                     isdot;          /* entry is "." */
83         int                     isdotdot;       /* entry is ".." */
84         xfs_mount_t             *mp;            /* mount structure pointer */
85         int                     namelen;        /* total name bytes */
86         xfs_ino_t               parent = 0;     /* parent inode number */
87         int                     size=0;         /* total computed size */
88
89         mp = dp->i_mount;
90
91         count = i8count = namelen = 0;
92         btp = xfs_dir2_block_tail_p(mp, block);
93         blp = xfs_dir2_block_leaf_p(btp);
94
95         /*
96          * Iterate over the block's data entries by using the leaf pointers.
97          */
98         for (i = 0; i < be32_to_cpu(btp->count); i++) {
99                 if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR)
100                         continue;
101                 /*
102                  * Calculate the pointer to the entry at hand.
103                  */
104                 dep = (xfs_dir2_data_entry_t *)
105                       ((char *)block + xfs_dir2_dataptr_to_off(mp, addr));
106                 /*
107                  * Detect . and .., so we can special-case them.
108                  * . is not included in sf directories.
109                  * .. is included by just the parent inode number.
110                  */
111                 isdot = dep->namelen == 1 && dep->name[0] == '.';
112                 isdotdot =
113                         dep->namelen == 2 &&
114                         dep->name[0] == '.' && dep->name[1] == '.';
115 #if XFS_BIG_INUMS
116                 if (!isdot)
117                         i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
118 #endif
119                 if (!isdot && !isdotdot) {
120                         count++;
121                         namelen += dep->namelen;
122                 } else if (isdotdot)
123                         parent = be64_to_cpu(dep->inumber);
124                 /*
125                  * Calculate the new size, see if we should give up yet.
126                  */
127                 size = xfs_dir2_sf_hdr_size(i8count) +          /* header */
128                        count +                                  /* namelen */
129                        count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */
130                        namelen +                                /* name */
131                        (i8count ?                               /* inumber */
132                                 (uint)sizeof(xfs_dir2_ino8_t) * count :
133                                 (uint)sizeof(xfs_dir2_ino4_t) * count);
134                 if (size > XFS_IFORK_DSIZE(dp))
135                         return size;            /* size value is a failure */
136         }
137         /*
138          * Create the output header, if it worked.
139          */
140         sfhp->count = count;
141         sfhp->i8count = i8count;
142         xfs_dir2_sf_put_inumber((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent);
143         return size;
144 }
145
146 /*
147  * Convert a block format directory to shortform.
148  * Caller has already checked that it will fit, and built us a header.
149  */
150 int                                             /* error */
151 xfs_dir2_block_to_sf(
152         xfs_da_args_t           *args,          /* operation arguments */
153         xfs_dabuf_t             *bp,            /* block buffer */
154         int                     size,           /* shortform directory size */
155         xfs_dir2_sf_hdr_t       *sfhp)          /* shortform directory hdr */
156 {
157         xfs_dir2_block_t        *block;         /* block structure */
158         xfs_dir2_block_tail_t   *btp;           /* block tail pointer */
159         xfs_dir2_data_entry_t   *dep;           /* data entry pointer */
160         xfs_inode_t             *dp;            /* incore directory inode */
161         xfs_dir2_data_unused_t  *dup;           /* unused data pointer */
162         char                    *endptr;        /* end of data entries */
163         int                     error;          /* error return value */
164         int                     logflags;       /* inode logging flags */
165         xfs_mount_t             *mp;            /* filesystem mount point */
166         char                    *ptr;           /* current data pointer */
167         xfs_dir2_sf_entry_t     *sfep;          /* shortform entry */
168         xfs_dir2_sf_t           *sfp;           /* shortform structure */
169         xfs_ino_t               temp;
170
171         xfs_dir2_trace_args_sb("block_to_sf", args, size, bp);
172         dp = args->dp;
173         mp = dp->i_mount;
174
175         /*
176          * Make a copy of the block data, so we can shrink the inode
177          * and add local data.
178          */
179         block = kmem_alloc(mp->m_dirblksize, KM_SLEEP);
180         memcpy(block, bp->data, mp->m_dirblksize);
181         logflags = XFS_ILOG_CORE;
182         if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) {
183                 ASSERT(error != ENOSPC);
184                 goto out;
185         }
186         /*
187          * The buffer is now unconditionally gone, whether
188          * xfs_dir2_shrink_inode worked or not.
189          *
190          * Convert the inode to local format.
191          */
192         dp->i_df.if_flags &= ~XFS_IFEXTENTS;
193         dp->i_df.if_flags |= XFS_IFINLINE;
194         dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
195         ASSERT(dp->i_df.if_bytes == 0);
196         xfs_idata_realloc(dp, size, XFS_DATA_FORK);
197         logflags |= XFS_ILOG_DDATA;
198         /*
199          * Copy the header into the newly allocate local space.
200          */
201         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
202         memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
203         dp->i_d.di_size = size;
204         /*
205          * Set up to loop over the block's entries.
206          */
207         btp = xfs_dir2_block_tail_p(mp, block);
208         ptr = (char *)block->u;
209         endptr = (char *)xfs_dir2_block_leaf_p(btp);
210         sfep = xfs_dir2_sf_firstentry(sfp);
211         /*
212          * Loop over the active and unused entries.
213          * Stop when we reach the leaf/tail portion of the block.
214          */
215         while (ptr < endptr) {
216                 /*
217                  * If it's unused, just skip over it.
218                  */
219                 dup = (xfs_dir2_data_unused_t *)ptr;
220                 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
221                         ptr += be16_to_cpu(dup->length);
222                         continue;
223                 }
224                 dep = (xfs_dir2_data_entry_t *)ptr;
225                 /*
226                  * Skip .
227                  */
228                 if (dep->namelen == 1 && dep->name[0] == '.')
229                         ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
230                 /*
231                  * Skip .., but make sure the inode number is right.
232                  */
233                 else if (dep->namelen == 2 &&
234                          dep->name[0] == '.' && dep->name[1] == '.')
235                         ASSERT(be64_to_cpu(dep->inumber) ==
236                                xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent));
237                 /*
238                  * Normal entry, copy it into shortform.
239                  */
240                 else {
241                         sfep->namelen = dep->namelen;
242                         xfs_dir2_sf_put_offset(sfep,
243                                 (xfs_dir2_data_aoff_t)
244                                 ((char *)dep - (char *)block));
245                         memcpy(sfep->name, dep->name, dep->namelen);
246                         temp = be64_to_cpu(dep->inumber);
247                         xfs_dir2_sf_put_inumber(sfp, &temp,
248                                 xfs_dir2_sf_inumberp(sfep));
249                         sfep = xfs_dir2_sf_nextentry(sfp, sfep);
250                 }
251                 ptr += xfs_dir2_data_entsize(dep->namelen);
252         }
253         ASSERT((char *)sfep - (char *)sfp == size);
254         xfs_dir2_sf_check(args);
255 out:
256         xfs_trans_log_inode(args->trans, dp, logflags);
257         kmem_free(block, mp->m_dirblksize);
258         return error;
259 }
260
261 /*
262  * Add a name to a shortform directory.
263  * There are two algorithms, "easy" and "hard" which we decide on
264  * before changing anything.
265  * Convert to block form if necessary, if the new entry won't fit.
266  */
267 int                                             /* error */
268 xfs_dir2_sf_addname(
269         xfs_da_args_t           *args)          /* operation arguments */
270 {
271         int                     add_entsize;    /* size of the new entry */
272         xfs_inode_t             *dp;            /* incore directory inode */
273         int                     error;          /* error return value */
274         int                     incr_isize;     /* total change in size */
275         int                     new_isize;      /* di_size after adding name */
276         int                     objchange;      /* changing to 8-byte inodes */
277         xfs_dir2_data_aoff_t    offset = 0;     /* offset for new entry */
278         int                     old_isize;      /* di_size before adding name */
279         int                     pick;           /* which algorithm to use */
280         xfs_dir2_sf_t           *sfp;           /* shortform structure */
281         xfs_dir2_sf_entry_t     *sfep = NULL;   /* shortform entry */
282
283         xfs_dir2_trace_args("sf_addname", args);
284         ASSERT(xfs_dir2_sf_lookup(args) == ENOENT);
285         dp = args->dp;
286         ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
287         /*
288          * Make sure the shortform value has some of its header.
289          */
290         if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
291                 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
292                 return XFS_ERROR(EIO);
293         }
294         ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
295         ASSERT(dp->i_df.if_u1.if_data != NULL);
296         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
297         ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
298         /*
299          * Compute entry (and change in) size.
300          */
301         add_entsize = xfs_dir2_sf_entsize_byname(sfp, args->namelen);
302         incr_isize = add_entsize;
303         objchange = 0;
304 #if XFS_BIG_INUMS
305         /*
306          * Do we have to change to 8 byte inodes?
307          */
308         if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) {
309                 /*
310                  * Yes, adjust the entry size and the total size.
311                  */
312                 add_entsize +=
313                         (uint)sizeof(xfs_dir2_ino8_t) -
314                         (uint)sizeof(xfs_dir2_ino4_t);
315                 incr_isize +=
316                         (sfp->hdr.count + 2) *
317                         ((uint)sizeof(xfs_dir2_ino8_t) -
318                          (uint)sizeof(xfs_dir2_ino4_t));
319                 objchange = 1;
320         }
321 #endif
322         old_isize = (int)dp->i_d.di_size;
323         new_isize = old_isize + incr_isize;
324         /*
325          * Won't fit as shortform any more (due to size),
326          * or the pick routine says it won't (due to offset values).
327          */
328         if (new_isize > XFS_IFORK_DSIZE(dp) ||
329             (pick =
330              xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) {
331                 /*
332                  * Just checking or no space reservation, it doesn't fit.
333                  */
334                 if (args->justcheck || args->total == 0)
335                         return XFS_ERROR(ENOSPC);
336                 /*
337                  * Convert to block form then add the name.
338                  */
339                 error = xfs_dir2_sf_to_block(args);
340                 if (error)
341                         return error;
342                 return xfs_dir2_block_addname(args);
343         }
344         /*
345          * Just checking, it fits.
346          */
347         if (args->justcheck)
348                 return 0;
349         /*
350          * Do it the easy way - just add it at the end.
351          */
352         if (pick == 1)
353                 xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize);
354         /*
355          * Do it the hard way - look for a place to insert the new entry.
356          * Convert to 8 byte inode numbers first if necessary.
357          */
358         else {
359                 ASSERT(pick == 2);
360 #if XFS_BIG_INUMS
361                 if (objchange)
362                         xfs_dir2_sf_toino8(args);
363 #endif
364                 xfs_dir2_sf_addname_hard(args, objchange, new_isize);
365         }
366         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
367         return 0;
368 }
369
370 /*
371  * Add the new entry the "easy" way.
372  * This is copying the old directory and adding the new entry at the end.
373  * Since it's sorted by "offset" we need room after the last offset
374  * that's already there, and then room to convert to a block directory.
375  * This is already checked by the pick routine.
376  */
377 static void
378 xfs_dir2_sf_addname_easy(
379         xfs_da_args_t           *args,          /* operation arguments */
380         xfs_dir2_sf_entry_t     *sfep,          /* pointer to new entry */
381         xfs_dir2_data_aoff_t    offset,         /* offset to use for new ent */
382         int                     new_isize)      /* new directory size */
383 {
384         int                     byteoff;        /* byte offset in sf dir */
385         xfs_inode_t             *dp;            /* incore directory inode */
386         xfs_dir2_sf_t           *sfp;           /* shortform structure */
387
388         dp = args->dp;
389
390         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
391         byteoff = (int)((char *)sfep - (char *)sfp);
392         /*
393          * Grow the in-inode space.
394          */
395         xfs_idata_realloc(dp, xfs_dir2_sf_entsize_byname(sfp, args->namelen),
396                 XFS_DATA_FORK);
397         /*
398          * Need to set up again due to realloc of the inode data.
399          */
400         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
401         sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff);
402         /*
403          * Fill in the new entry.
404          */
405         sfep->namelen = args->namelen;
406         xfs_dir2_sf_put_offset(sfep, offset);
407         memcpy(sfep->name, args->name, sfep->namelen);
408         xfs_dir2_sf_put_inumber(sfp, &args->inumber,
409                 xfs_dir2_sf_inumberp(sfep));
410         /*
411          * Update the header and inode.
412          */
413         sfp->hdr.count++;
414 #if XFS_BIG_INUMS
415         if (args->inumber > XFS_DIR2_MAX_SHORT_INUM)
416                 sfp->hdr.i8count++;
417 #endif
418         dp->i_d.di_size = new_isize;
419         xfs_dir2_sf_check(args);
420 }
421
422 /*
423  * Add the new entry the "hard" way.
424  * The caller has already converted to 8 byte inode numbers if necessary,
425  * in which case we need to leave the i8count at 1.
426  * Find a hole that the new entry will fit into, and copy
427  * the first part of the entries, the new entry, and the last part of
428  * the entries.
429  */
430 /* ARGSUSED */
431 static void
432 xfs_dir2_sf_addname_hard(
433         xfs_da_args_t           *args,          /* operation arguments */
434         int                     objchange,      /* changing inode number size */
435         int                     new_isize)      /* new directory size */
436 {
437         int                     add_datasize;   /* data size need for new ent */
438         char                    *buf;           /* buffer for old */
439         xfs_inode_t             *dp;            /* incore directory inode */
440         int                     eof;            /* reached end of old dir */
441         int                     nbytes;         /* temp for byte copies */
442         xfs_dir2_data_aoff_t    new_offset;     /* next offset value */
443         xfs_dir2_data_aoff_t    offset;         /* current offset value */
444         int                     old_isize;      /* previous di_size */
445         xfs_dir2_sf_entry_t     *oldsfep;       /* entry in original dir */
446         xfs_dir2_sf_t           *oldsfp;        /* original shortform dir */
447         xfs_dir2_sf_entry_t     *sfep;          /* entry in new dir */
448         xfs_dir2_sf_t           *sfp;           /* new shortform dir */
449
450         /*
451          * Copy the old directory to the stack buffer.
452          */
453         dp = args->dp;
454
455         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
456         old_isize = (int)dp->i_d.di_size;
457         buf = kmem_alloc(old_isize, KM_SLEEP);
458         oldsfp = (xfs_dir2_sf_t *)buf;
459         memcpy(oldsfp, sfp, old_isize);
460         /*
461          * Loop over the old directory finding the place we're going
462          * to insert the new entry.
463          * If it's going to end up at the end then oldsfep will point there.
464          */
465         for (offset = XFS_DIR2_DATA_FIRST_OFFSET,
466               oldsfep = xfs_dir2_sf_firstentry(oldsfp),
467               add_datasize = xfs_dir2_data_entsize(args->namelen),
468               eof = (char *)oldsfep == &buf[old_isize];
469              !eof;
470              offset = new_offset + xfs_dir2_data_entsize(oldsfep->namelen),
471               oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep),
472               eof = (char *)oldsfep == &buf[old_isize]) {
473                 new_offset = xfs_dir2_sf_get_offset(oldsfep);
474                 if (offset + add_datasize <= new_offset)
475                         break;
476         }
477         /*
478          * Get rid of the old directory, then allocate space for
479          * the new one.  We do this so xfs_idata_realloc won't copy
480          * the data.
481          */
482         xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK);
483         xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK);
484         /*
485          * Reset the pointer since the buffer was reallocated.
486          */
487         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
488         /*
489          * Copy the first part of the directory, including the header.
490          */
491         nbytes = (int)((char *)oldsfep - (char *)oldsfp);
492         memcpy(sfp, oldsfp, nbytes);
493         sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
494         /*
495          * Fill in the new entry, and update the header counts.
496          */
497         sfep->namelen = args->namelen;
498         xfs_dir2_sf_put_offset(sfep, offset);
499         memcpy(sfep->name, args->name, sfep->namelen);
500         xfs_dir2_sf_put_inumber(sfp, &args->inumber,
501                 xfs_dir2_sf_inumberp(sfep));
502         sfp->hdr.count++;
503 #if XFS_BIG_INUMS
504         if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
505                 sfp->hdr.i8count++;
506 #endif
507         /*
508          * If there's more left to copy, do that.
509          */
510         if (!eof) {
511                 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
512                 memcpy(sfep, oldsfep, old_isize - nbytes);
513         }
514         kmem_free(buf, old_isize);
515         dp->i_d.di_size = new_isize;
516         xfs_dir2_sf_check(args);
517 }
518
519 /*
520  * Decide if the new entry will fit at all.
521  * If it will fit, pick between adding the new entry to the end (easy)
522  * or somewhere else (hard).
523  * Return 0 (won't fit), 1 (easy), 2 (hard).
524  */
525 /*ARGSUSED*/
526 static int                                      /* pick result */
527 xfs_dir2_sf_addname_pick(
528         xfs_da_args_t           *args,          /* operation arguments */
529         int                     objchange,      /* inode # size changes */
530         xfs_dir2_sf_entry_t     **sfepp,        /* out(1): new entry ptr */
531         xfs_dir2_data_aoff_t    *offsetp)       /* out(1): new offset */
532 {
533         xfs_inode_t             *dp;            /* incore directory inode */
534         int                     holefit;        /* found hole it will fit in */
535         int                     i;              /* entry number */
536         xfs_mount_t             *mp;            /* filesystem mount point */
537         xfs_dir2_data_aoff_t    offset;         /* data block offset */
538         xfs_dir2_sf_entry_t     *sfep;          /* shortform entry */
539         xfs_dir2_sf_t           *sfp;           /* shortform structure */
540         int                     size;           /* entry's data size */
541         int                     used;           /* data bytes used */
542
543         dp = args->dp;
544         mp = dp->i_mount;
545
546         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
547         size = xfs_dir2_data_entsize(args->namelen);
548         offset = XFS_DIR2_DATA_FIRST_OFFSET;
549         sfep = xfs_dir2_sf_firstentry(sfp);
550         holefit = 0;
551         /*
552          * Loop over sf entries.
553          * Keep track of data offset and whether we've seen a place
554          * to insert the new entry.
555          */
556         for (i = 0; i < sfp->hdr.count; i++) {
557                 if (!holefit)
558                         holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
559                 offset = xfs_dir2_sf_get_offset(sfep) +
560                          xfs_dir2_data_entsize(sfep->namelen);
561                 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
562         }
563         /*
564          * Calculate data bytes used excluding the new entry, if this
565          * was a data block (block form directory).
566          */
567         used = offset +
568                (sfp->hdr.count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
569                (uint)sizeof(xfs_dir2_block_tail_t);
570         /*
571          * If it won't fit in a block form then we can't insert it,
572          * we'll go back, convert to block, then try the insert and convert
573          * to leaf.
574          */
575         if (used + (holefit ? 0 : size) > mp->m_dirblksize)
576                 return 0;
577         /*
578          * If changing the inode number size, do it the hard way.
579          */
580 #if XFS_BIG_INUMS
581         if (objchange) {
582                 return 2;
583         }
584 #else
585         ASSERT(objchange == 0);
586 #endif
587         /*
588          * If it won't fit at the end then do it the hard way (use the hole).
589          */
590         if (used + size > mp->m_dirblksize)
591                 return 2;
592         /*
593          * Do it the easy way.
594          */
595         *sfepp = sfep;
596         *offsetp = offset;
597         return 1;
598 }
599
600 #ifdef DEBUG
601 /*
602  * Check consistency of shortform directory, assert if bad.
603  */
604 static void
605 xfs_dir2_sf_check(
606         xfs_da_args_t           *args)          /* operation arguments */
607 {
608         xfs_inode_t             *dp;            /* incore directory inode */
609         int                     i;              /* entry number */
610         int                     i8count;        /* number of big inode#s */
611         xfs_ino_t               ino;            /* entry inode number */
612         int                     offset;         /* data offset */
613         xfs_dir2_sf_entry_t     *sfep;          /* shortform dir entry */
614         xfs_dir2_sf_t           *sfp;           /* shortform structure */
615
616         dp = args->dp;
617
618         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
619         offset = XFS_DIR2_DATA_FIRST_OFFSET;
620         ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
621         i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
622
623         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
624              i < sfp->hdr.count;
625              i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
626                 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
627                 ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
628                 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
629                 offset =
630                         xfs_dir2_sf_get_offset(sfep) +
631                         xfs_dir2_data_entsize(sfep->namelen);
632         }
633         ASSERT(i8count == sfp->hdr.i8count);
634         ASSERT(XFS_BIG_INUMS || i8count == 0);
635         ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
636         ASSERT(offset +
637                (sfp->hdr.count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
638                (uint)sizeof(xfs_dir2_block_tail_t) <=
639                dp->i_mount->m_dirblksize);
640 }
641 #endif  /* DEBUG */
642
643 /*
644  * Create a new (shortform) directory.
645  */
646 int                                     /* error, always 0 */
647 xfs_dir2_sf_create(
648         xfs_da_args_t   *args,          /* operation arguments */
649         xfs_ino_t       pino)           /* parent inode number */
650 {
651         xfs_inode_t     *dp;            /* incore directory inode */
652         int             i8count;        /* parent inode is an 8-byte number */
653         xfs_dir2_sf_t   *sfp;           /* shortform structure */
654         int             size;           /* directory size */
655
656         xfs_dir2_trace_args_i("sf_create", args, pino);
657         dp = args->dp;
658
659         ASSERT(dp != NULL);
660         ASSERT(dp->i_d.di_size == 0);
661         /*
662          * If it's currently a zero-length extent file,
663          * convert it to local format.
664          */
665         if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) {
666                 dp->i_df.if_flags &= ~XFS_IFEXTENTS;    /* just in case */
667                 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
668                 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
669                 dp->i_df.if_flags |= XFS_IFINLINE;
670         }
671         ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
672         ASSERT(dp->i_df.if_bytes == 0);
673         i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
674         size = xfs_dir2_sf_hdr_size(i8count);
675         /*
676          * Make a buffer for the data.
677          */
678         xfs_idata_realloc(dp, size, XFS_DATA_FORK);
679         /*
680          * Fill in the header,
681          */
682         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
683         sfp->hdr.i8count = i8count;
684         /*
685          * Now can put in the inode number, since i8count is set.
686          */
687         xfs_dir2_sf_put_inumber(sfp, &pino, &sfp->hdr.parent);
688         sfp->hdr.count = 0;
689         dp->i_d.di_size = size;
690         xfs_dir2_sf_check(args);
691         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
692         return 0;
693 }
694
695 int                                             /* error */
696 xfs_dir2_sf_getdents(
697         xfs_inode_t             *dp,            /* incore directory inode */
698         uio_t                   *uio,           /* caller's buffer control */
699         int                     *eofp,          /* eof reached? (out) */
700         xfs_dirent_t            *dbp,           /* caller's buffer */
701         xfs_dir2_put_t          put)            /* abi's formatting function */
702 {
703         int                     error;          /* error return value */
704         int                     i;              /* shortform entry number */
705         xfs_mount_t             *mp;            /* filesystem mount point */
706         xfs_dir2_dataptr_t      off;            /* current entry's offset */
707         xfs_dir2_put_args_t     p;              /* arg package for put rtn */
708         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
709         xfs_dir2_sf_t           *sfp;           /* shortform structure */
710         xfs_off_t                       dir_offset;
711
712         mp = dp->i_mount;
713
714         ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
715         /*
716          * Give up if the directory is way too short.
717          */
718         if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
719                 ASSERT(XFS_FORCED_SHUTDOWN(mp));
720                 return XFS_ERROR(EIO);
721         }
722
723         dir_offset = uio->uio_offset;
724
725         ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
726         ASSERT(dp->i_df.if_u1.if_data != NULL);
727
728         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
729
730         ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
731
732         /*
733          * If the block number in the offset is out of range, we're done.
734          */
735         if (xfs_dir2_dataptr_to_db(mp, dir_offset) > mp->m_dirdatablk) {
736                 *eofp = 1;
737                 return 0;
738         }
739
740         /*
741          * Set up putargs structure.
742          */
743         p.dbp = dbp;
744         p.put = put;
745         p.uio = uio;
746         /*
747          * Put . entry unless we're starting past it.
748          */
749         if (dir_offset <=
750                     xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
751                                                XFS_DIR2_DATA_DOT_OFFSET)) {
752                 p.cook = xfs_dir2_db_off_to_dataptr(mp, 0,
753                                                 XFS_DIR2_DATA_DOTDOT_OFFSET);
754                 p.ino = dp->i_ino;
755 #if XFS_BIG_INUMS
756                 p.ino += mp->m_inoadd;
757 #endif
758                 p.name = ".";
759                 p.namelen = 1;
760
761                 error = p.put(&p);
762
763                 if (!p.done) {
764                         uio->uio_offset =
765                                 xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
766                                                 XFS_DIR2_DATA_DOT_OFFSET);
767                         return error;
768                 }
769         }
770
771         /*
772          * Put .. entry unless we're starting past it.
773          */
774         if (dir_offset <=
775                     xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
776                                                XFS_DIR2_DATA_DOTDOT_OFFSET)) {
777                 p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
778                                                 XFS_DIR2_DATA_FIRST_OFFSET);
779                 p.ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
780 #if XFS_BIG_INUMS
781                 p.ino += mp->m_inoadd;
782 #endif
783                 p.name = "..";
784                 p.namelen = 2;
785
786                 error = p.put(&p);
787
788                 if (!p.done) {
789                         uio->uio_offset =
790                                 xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
791                                         XFS_DIR2_DATA_DOTDOT_OFFSET);
792                         return error;
793                 }
794         }
795
796         /*
797          * Loop while there are more entries and put'ing works.
798          */
799         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
800                      i < sfp->hdr.count;
801                              i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
802
803                 off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
804                                 xfs_dir2_sf_get_offset(sfep));
805
806                 if (dir_offset > off)
807                         continue;
808
809                 p.namelen = sfep->namelen;
810
811                 p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
812                         xfs_dir2_sf_get_offset(sfep) +
813                         xfs_dir2_data_entsize(p.namelen));
814
815                 p.ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
816 #if XFS_BIG_INUMS
817                 p.ino += mp->m_inoadd;
818 #endif
819                 p.name = (char *)sfep->name;
820
821                 error = p.put(&p);
822
823                 if (!p.done) {
824                         uio->uio_offset = off;
825                         return error;
826                 }
827         }
828
829         /*
830          * They all fit.
831          */
832         *eofp = 1;
833
834         uio->uio_offset =
835                 xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
836
837         return 0;
838 }
839
840 /*
841  * Lookup an entry in a shortform directory.
842  * Returns EEXIST if found, ENOENT if not found.
843  */
844 int                                             /* error */
845 xfs_dir2_sf_lookup(
846         xfs_da_args_t           *args)          /* operation arguments */
847 {
848         xfs_inode_t             *dp;            /* incore directory inode */
849         int                     i;              /* entry index */
850         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
851         xfs_dir2_sf_t           *sfp;           /* shortform structure */
852
853         xfs_dir2_trace_args("sf_lookup", args);
854         xfs_dir2_sf_check(args);
855         dp = args->dp;
856
857         ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
858         /*
859          * Bail out if the directory is way too short.
860          */
861         if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
862                 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
863                 return XFS_ERROR(EIO);
864         }
865         ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
866         ASSERT(dp->i_df.if_u1.if_data != NULL);
867         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
868         ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
869         /*
870          * Special case for .
871          */
872         if (args->namelen == 1 && args->name[0] == '.') {
873                 args->inumber = dp->i_ino;
874                 return XFS_ERROR(EEXIST);
875         }
876         /*
877          * Special case for ..
878          */
879         if (args->namelen == 2 &&
880             args->name[0] == '.' && args->name[1] == '.') {
881                 args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
882                 return XFS_ERROR(EEXIST);
883         }
884         /*
885          * Loop over all the entries trying to match ours.
886          */
887         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
888              i < sfp->hdr.count;
889              i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
890                 if (sfep->namelen == args->namelen &&
891                     sfep->name[0] == args->name[0] &&
892                     memcmp(args->name, sfep->name, args->namelen) == 0) {
893                         args->inumber =
894                                 xfs_dir2_sf_get_inumber(sfp,
895                                         xfs_dir2_sf_inumberp(sfep));
896                         return XFS_ERROR(EEXIST);
897                 }
898         }
899         /*
900          * Didn't find it.
901          */
902         ASSERT(args->oknoent);
903         return XFS_ERROR(ENOENT);
904 }
905
906 /*
907  * Remove an entry from a shortform directory.
908  */
909 int                                             /* error */
910 xfs_dir2_sf_removename(
911         xfs_da_args_t           *args)
912 {
913         int                     byteoff;        /* offset of removed entry */
914         xfs_inode_t             *dp;            /* incore directory inode */
915         int                     entsize;        /* this entry's size */
916         int                     i;              /* shortform entry index */
917         int                     newsize;        /* new inode size */
918         int                     oldsize;        /* old inode size */
919         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
920         xfs_dir2_sf_t           *sfp;           /* shortform structure */
921
922         xfs_dir2_trace_args("sf_removename", args);
923         dp = args->dp;
924
925         ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
926         oldsize = (int)dp->i_d.di_size;
927         /*
928          * Bail out if the directory is way too short.
929          */
930         if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) {
931                 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
932                 return XFS_ERROR(EIO);
933         }
934         ASSERT(dp->i_df.if_bytes == oldsize);
935         ASSERT(dp->i_df.if_u1.if_data != NULL);
936         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
937         ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
938         /*
939          * Loop over the old directory entries.
940          * Find the one we're deleting.
941          */
942         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
943              i < sfp->hdr.count;
944              i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
945                 if (sfep->namelen == args->namelen &&
946                     sfep->name[0] == args->name[0] &&
947                     memcmp(sfep->name, args->name, args->namelen) == 0) {
948                         ASSERT(xfs_dir2_sf_get_inumber(sfp,
949                                         xfs_dir2_sf_inumberp(sfep)) ==
950                                 args->inumber);
951                         break;
952                 }
953         }
954         /*
955          * Didn't find it.
956          */
957         if (i == sfp->hdr.count) {
958                 return XFS_ERROR(ENOENT);
959         }
960         /*
961          * Calculate sizes.
962          */
963         byteoff = (int)((char *)sfep - (char *)sfp);
964         entsize = xfs_dir2_sf_entsize_byname(sfp, args->namelen);
965         newsize = oldsize - entsize;
966         /*
967          * Copy the part if any after the removed entry, sliding it down.
968          */
969         if (byteoff + entsize < oldsize)
970                 memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
971                         oldsize - (byteoff + entsize));
972         /*
973          * Fix up the header and file size.
974          */
975         sfp->hdr.count--;
976         dp->i_d.di_size = newsize;
977         /*
978          * Reallocate, making it smaller.
979          */
980         xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK);
981         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
982 #if XFS_BIG_INUMS
983         /*
984          * Are we changing inode number size?
985          */
986         if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
987                 if (sfp->hdr.i8count == 1)
988                         xfs_dir2_sf_toino4(args);
989                 else
990                         sfp->hdr.i8count--;
991         }
992 #endif
993         xfs_dir2_sf_check(args);
994         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
995         return 0;
996 }
997
998 /*
999  * Replace the inode number of an entry in a shortform directory.
1000  */
1001 int                                             /* error */
1002 xfs_dir2_sf_replace(
1003         xfs_da_args_t           *args)          /* operation arguments */
1004 {
1005         xfs_inode_t             *dp;            /* incore directory inode */
1006         int                     i;              /* entry index */
1007 #if XFS_BIG_INUMS || defined(DEBUG)
1008         xfs_ino_t               ino=0;          /* entry old inode number */
1009 #endif
1010 #if XFS_BIG_INUMS
1011         int                     i8elevated;     /* sf_toino8 set i8count=1 */
1012 #endif
1013         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
1014         xfs_dir2_sf_t           *sfp;           /* shortform structure */
1015
1016         xfs_dir2_trace_args("sf_replace", args);
1017         dp = args->dp;
1018
1019         ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
1020         /*
1021          * Bail out if the shortform directory is way too small.
1022          */
1023         if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
1024                 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
1025                 return XFS_ERROR(EIO);
1026         }
1027         ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
1028         ASSERT(dp->i_df.if_u1.if_data != NULL);
1029         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1030         ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
1031 #if XFS_BIG_INUMS
1032         /*
1033          * New inode number is large, and need to convert to 8-byte inodes.
1034          */
1035         if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) {
1036                 int     error;                  /* error return value */
1037                 int     newsize;                /* new inode size */
1038
1039                 newsize =
1040                         dp->i_df.if_bytes +
1041                         (sfp->hdr.count + 1) *
1042                         ((uint)sizeof(xfs_dir2_ino8_t) -
1043                          (uint)sizeof(xfs_dir2_ino4_t));
1044                 /*
1045                  * Won't fit as shortform, convert to block then do replace.
1046                  */
1047                 if (newsize > XFS_IFORK_DSIZE(dp)) {
1048                         error = xfs_dir2_sf_to_block(args);
1049                         if (error) {
1050                                 return error;
1051                         }
1052                         return xfs_dir2_block_replace(args);
1053                 }
1054                 /*
1055                  * Still fits, convert to 8-byte now.
1056                  */
1057                 xfs_dir2_sf_toino8(args);
1058                 i8elevated = 1;
1059                 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1060         } else
1061                 i8elevated = 0;
1062 #endif
1063         ASSERT(args->namelen != 1 || args->name[0] != '.');
1064         /*
1065          * Replace ..'s entry.
1066          */
1067         if (args->namelen == 2 &&
1068             args->name[0] == '.' && args->name[1] == '.') {
1069 #if XFS_BIG_INUMS || defined(DEBUG)
1070                 ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
1071                 ASSERT(args->inumber != ino);
1072 #endif
1073                 xfs_dir2_sf_put_inumber(sfp, &args->inumber, &sfp->hdr.parent);
1074         }
1075         /*
1076          * Normal entry, look for the name.
1077          */
1078         else {
1079                 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
1080                      i < sfp->hdr.count;
1081                      i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
1082                         if (sfep->namelen == args->namelen &&
1083                             sfep->name[0] == args->name[0] &&
1084                             memcmp(args->name, sfep->name, args->namelen) == 0) {
1085 #if XFS_BIG_INUMS || defined(DEBUG)
1086                                 ino = xfs_dir2_sf_get_inumber(sfp,
1087                                         xfs_dir2_sf_inumberp(sfep));
1088                                 ASSERT(args->inumber != ino);
1089 #endif
1090                                 xfs_dir2_sf_put_inumber(sfp, &args->inumber,
1091                                         xfs_dir2_sf_inumberp(sfep));
1092                                 break;
1093                         }
1094                 }
1095                 /*
1096                  * Didn't find it.
1097                  */
1098                 if (i == sfp->hdr.count) {
1099                         ASSERT(args->oknoent);
1100 #if XFS_BIG_INUMS
1101                         if (i8elevated)
1102                                 xfs_dir2_sf_toino4(args);
1103 #endif
1104                         return XFS_ERROR(ENOENT);
1105                 }
1106         }
1107 #if XFS_BIG_INUMS
1108         /*
1109          * See if the old number was large, the new number is small.
1110          */
1111         if (ino > XFS_DIR2_MAX_SHORT_INUM &&
1112             args->inumber <= XFS_DIR2_MAX_SHORT_INUM) {
1113                 /*
1114                  * And the old count was one, so need to convert to small.
1115                  */
1116                 if (sfp->hdr.i8count == 1)
1117                         xfs_dir2_sf_toino4(args);
1118                 else
1119                         sfp->hdr.i8count--;
1120         }
1121         /*
1122          * See if the old number was small, the new number is large.
1123          */
1124         if (ino <= XFS_DIR2_MAX_SHORT_INUM &&
1125             args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
1126                 /*
1127                  * add to the i8count unless we just converted to 8-byte
1128                  * inodes (which does an implied i8count = 1)
1129                  */
1130                 ASSERT(sfp->hdr.i8count != 0);
1131                 if (!i8elevated)
1132                         sfp->hdr.i8count++;
1133         }
1134 #endif
1135         xfs_dir2_sf_check(args);
1136         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
1137         return 0;
1138 }
1139
1140 #if XFS_BIG_INUMS
1141 /*
1142  * Convert from 8-byte inode numbers to 4-byte inode numbers.
1143  * The last 8-byte inode number is gone, but the count is still 1.
1144  */
1145 static void
1146 xfs_dir2_sf_toino4(
1147         xfs_da_args_t           *args)          /* operation arguments */
1148 {
1149         char                    *buf;           /* old dir's buffer */
1150         xfs_inode_t             *dp;            /* incore directory inode */
1151         int                     i;              /* entry index */
1152         xfs_ino_t               ino;            /* entry inode number */
1153         int                     newsize;        /* new inode size */
1154         xfs_dir2_sf_entry_t     *oldsfep;       /* old sf entry */
1155         xfs_dir2_sf_t           *oldsfp;        /* old sf directory */
1156         int                     oldsize;        /* old inode size */
1157         xfs_dir2_sf_entry_t     *sfep;          /* new sf entry */
1158         xfs_dir2_sf_t           *sfp;           /* new sf directory */
1159
1160         xfs_dir2_trace_args("sf_toino4", args);
1161         dp = args->dp;
1162
1163         /*
1164          * Copy the old directory to the buffer.
1165          * Then nuke it from the inode, and add the new buffer to the inode.
1166          * Don't want xfs_idata_realloc copying the data here.
1167          */
1168         oldsize = dp->i_df.if_bytes;
1169         buf = kmem_alloc(oldsize, KM_SLEEP);
1170         oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1171         ASSERT(oldsfp->hdr.i8count == 1);
1172         memcpy(buf, oldsfp, oldsize);
1173         /*
1174          * Compute the new inode size.
1175          */
1176         newsize =
1177                 oldsize -
1178                 (oldsfp->hdr.count + 1) *
1179                 ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t));
1180         xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1181         xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1182         /*
1183          * Reset our pointers, the data has moved.
1184          */
1185         oldsfp = (xfs_dir2_sf_t *)buf;
1186         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1187         /*
1188          * Fill in the new header.
1189          */
1190         sfp->hdr.count = oldsfp->hdr.count;
1191         sfp->hdr.i8count = 0;
1192         ino = xfs_dir2_sf_get_inumber(oldsfp, &oldsfp->hdr.parent);
1193         xfs_dir2_sf_put_inumber(sfp, &ino, &sfp->hdr.parent);
1194         /*
1195          * Copy the entries field by field.
1196          */
1197         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1198                     oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1199              i < sfp->hdr.count;
1200              i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
1201                   oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
1202                 sfep->namelen = oldsfep->namelen;
1203                 sfep->offset = oldsfep->offset;
1204                 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1205                 ino = xfs_dir2_sf_get_inumber(oldsfp,
1206                         xfs_dir2_sf_inumberp(oldsfep));
1207                 xfs_dir2_sf_put_inumber(sfp, &ino, xfs_dir2_sf_inumberp(sfep));
1208         }
1209         /*
1210          * Clean up the inode.
1211          */
1212         kmem_free(buf, oldsize);
1213         dp->i_d.di_size = newsize;
1214         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1215 }
1216
1217 /*
1218  * Convert from 4-byte inode numbers to 8-byte inode numbers.
1219  * The new 8-byte inode number is not there yet, we leave with the
1220  * count 1 but no corresponding entry.
1221  */
1222 static void
1223 xfs_dir2_sf_toino8(
1224         xfs_da_args_t           *args)          /* operation arguments */
1225 {
1226         char                    *buf;           /* old dir's buffer */
1227         xfs_inode_t             *dp;            /* incore directory inode */
1228         int                     i;              /* entry index */
1229         xfs_ino_t               ino;            /* entry inode number */
1230         int                     newsize;        /* new inode size */
1231         xfs_dir2_sf_entry_t     *oldsfep;       /* old sf entry */
1232         xfs_dir2_sf_t           *oldsfp;        /* old sf directory */
1233         int                     oldsize;        /* old inode size */
1234         xfs_dir2_sf_entry_t     *sfep;          /* new sf entry */
1235         xfs_dir2_sf_t           *sfp;           /* new sf directory */
1236
1237         xfs_dir2_trace_args("sf_toino8", args);
1238         dp = args->dp;
1239
1240         /*
1241          * Copy the old directory to the buffer.
1242          * Then nuke it from the inode, and add the new buffer to the inode.
1243          * Don't want xfs_idata_realloc copying the data here.
1244          */
1245         oldsize = dp->i_df.if_bytes;
1246         buf = kmem_alloc(oldsize, KM_SLEEP);
1247         oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1248         ASSERT(oldsfp->hdr.i8count == 0);
1249         memcpy(buf, oldsfp, oldsize);
1250         /*
1251          * Compute the new inode size.
1252          */
1253         newsize =
1254                 oldsize +
1255                 (oldsfp->hdr.count + 1) *
1256                 ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t));
1257         xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1258         xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1259         /*
1260          * Reset our pointers, the data has moved.
1261          */
1262         oldsfp = (xfs_dir2_sf_t *)buf;
1263         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1264         /*
1265          * Fill in the new header.
1266          */
1267         sfp->hdr.count = oldsfp->hdr.count;
1268         sfp->hdr.i8count = 1;
1269         ino = xfs_dir2_sf_get_inumber(oldsfp, &oldsfp->hdr.parent);
1270         xfs_dir2_sf_put_inumber(sfp, &ino, &sfp->hdr.parent);
1271         /*
1272          * Copy the entries field by field.
1273          */
1274         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1275                     oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1276              i < sfp->hdr.count;
1277              i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
1278                   oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
1279                 sfep->namelen = oldsfep->namelen;
1280                 sfep->offset = oldsfep->offset;
1281                 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1282                 ino = xfs_dir2_sf_get_inumber(oldsfp,
1283                         xfs_dir2_sf_inumberp(oldsfep));
1284                 xfs_dir2_sf_put_inumber(sfp, &ino, xfs_dir2_sf_inumberp(sfep));
1285         }
1286         /*
1287          * Clean up the inode.
1288          */
1289         kmem_free(buf, oldsize);
1290         dp->i_d.di_size = newsize;
1291         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1292 }
1293 #endif  /* XFS_BIG_INUMS */