blob: 6a4d8caaba7bd4ca7517847053c02f80055fc6b2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Nathan Scott7b718762005-11-02 14:58:39 +11002 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Nathan Scott7b718762005-11-02 14:58:39 +11005 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * published by the Free Software Foundation.
8 *
Nathan Scott7b718762005-11-02 14:58:39 +11009 * 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Nathan Scott7b718762005-11-02 14:58:39 +110014 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "xfs.h"
Nathan Scotta844f452005-11-02 14:38:42 +110019#include "xfs_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include "xfs_types.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include "xfs_log.h"
Nathan Scotta844f452005-11-02 14:38:42 +110022#include "xfs_inum.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include "xfs_trans.h"
24#include "xfs_sb.h"
25#include "xfs_dir.h"
26#include "xfs_dir2.h"
27#include "xfs_dmapi.h"
28#include "xfs_mount.h"
Nathan Scotta844f452005-11-02 14:38:42 +110029#include "xfs_da_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include "xfs_bmap_btree.h"
Nathan Scotta844f452005-11-02 14:38:42 +110031#include "xfs_alloc_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "xfs_ialloc_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include "xfs_dir_sf.h"
34#include "xfs_dir2_sf.h"
Nathan Scotta844f452005-11-02 14:38:42 +110035#include "xfs_attr_sf.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include "xfs_dinode.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "xfs_inode.h"
Nathan Scotta844f452005-11-02 14:38:42 +110038#include "xfs_inode_item.h"
39#include "xfs_alloc.h"
40#include "xfs_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include "xfs_bmap.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "xfs_dir_leaf.h"
43#include "xfs_error.h"
44
45/*
46 * xfs_dir_leaf.c
47 *
48 * Routines to implement leaf blocks of directories as Btrees of hashed names.
49 */
50
51/*========================================================================
52 * Function prototypes for the kernel.
53 *========================================================================*/
54
55/*
56 * Routines used for growing the Btree.
57 */
58STATIC void xfs_dir_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args,
59 int insertion_index,
60 int freemap_index);
61STATIC int xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer,
62 int musthave, int justcheck);
63STATIC void xfs_dir_leaf_rebalance(xfs_da_state_t *state,
64 xfs_da_state_blk_t *blk1,
65 xfs_da_state_blk_t *blk2);
66STATIC int xfs_dir_leaf_figure_balance(xfs_da_state_t *state,
67 xfs_da_state_blk_t *leaf_blk_1,
68 xfs_da_state_blk_t *leaf_blk_2,
69 int *number_entries_in_blk1,
70 int *number_namebytes_in_blk1);
71
Christoph Hellwigba0f32d2005-06-21 15:36:52 +100072STATIC int xfs_dir_leaf_create(struct xfs_da_args *args,
73 xfs_dablk_t which_block,
74 struct xfs_dabuf **bpp);
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076/*
77 * Utility routines.
78 */
79STATIC void xfs_dir_leaf_moveents(xfs_dir_leafblock_t *src_leaf,
80 int src_start,
81 xfs_dir_leafblock_t *dst_leaf,
82 int dst_start, int move_count,
83 xfs_mount_t *mp);
84
85
86/*========================================================================
87 * External routines when dirsize < XFS_IFORK_DSIZE(dp).
88 *========================================================================*/
89
90
91/*
92 * Validate a given inode number.
93 */
94int
95xfs_dir_ino_validate(xfs_mount_t *mp, xfs_ino_t ino)
96{
97 xfs_agblock_t agblkno;
98 xfs_agino_t agino;
99 xfs_agnumber_t agno;
100 int ino_ok;
101 int ioff;
102
103 agno = XFS_INO_TO_AGNO(mp, ino);
104 agblkno = XFS_INO_TO_AGBNO(mp, ino);
105 ioff = XFS_INO_TO_OFFSET(mp, ino);
106 agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff);
107 ino_ok =
108 agno < mp->m_sb.sb_agcount &&
109 agblkno < mp->m_sb.sb_agblocks &&
110 agblkno != 0 &&
111 ioff < (1 << mp->m_sb.sb_inopblog) &&
112 XFS_AGINO_TO_INO(mp, agno, agino) == ino;
113 if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
114 XFS_RANDOM_DIR_INO_VALIDATE))) {
115 xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx",
116 (unsigned long long) ino);
117 XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
118 return XFS_ERROR(EFSCORRUPTED);
119 }
120 return 0;
121}
122
123/*
124 * Create the initial contents of a shortform directory.
125 */
126int
127xfs_dir_shortform_create(xfs_da_args_t *args, xfs_ino_t parent)
128{
129 xfs_dir_sf_hdr_t *hdr;
130 xfs_inode_t *dp;
131
132 dp = args->dp;
133 ASSERT(dp != NULL);
134 ASSERT(dp->i_d.di_size == 0);
135 if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) {
136 dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */
137 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
138 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
139 dp->i_df.if_flags |= XFS_IFINLINE;
140 }
141 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
142 ASSERT(dp->i_df.if_bytes == 0);
143 xfs_idata_realloc(dp, sizeof(*hdr), XFS_DATA_FORK);
144 hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data;
145 XFS_DIR_SF_PUT_DIRINO(&parent, &hdr->parent);
146
147 hdr->count = 0;
148 dp->i_d.di_size = sizeof(*hdr);
149 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
Jesper Juhl014c2542006-01-15 02:37:08 +0100150 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151}
152
153/*
154 * Add a name to the shortform directory structure.
155 * Overflow from the inode has already been checked for.
156 */
157int
158xfs_dir_shortform_addname(xfs_da_args_t *args)
159{
160 xfs_dir_shortform_t *sf;
161 xfs_dir_sf_entry_t *sfe;
162 int i, offset, size;
163 xfs_inode_t *dp;
164
165 dp = args->dp;
166 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
167 /*
168 * Catch the case where the conversion from shortform to leaf
169 * failed part way through.
170 */
171 if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
172 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
173 return XFS_ERROR(EIO);
174 }
175 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
176 ASSERT(dp->i_df.if_u1.if_data != NULL);
177 sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
178 sfe = &sf->list[0];
Nathan Scottb2fc6ad2006-03-17 17:30:01 +1100179 for (i = sf->hdr.count-1; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 if (sfe->namelen == args->namelen &&
181 args->name[0] == sfe->name[0] &&
182 memcmp(args->name, sfe->name, args->namelen) == 0)
Jesper Juhl014c2542006-01-15 02:37:08 +0100183 return XFS_ERROR(EEXIST);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 sfe = XFS_DIR_SF_NEXTENTRY(sfe);
185 }
186
187 offset = (int)((char *)sfe - (char *)sf);
188 size = XFS_DIR_SF_ENTSIZE_BYNAME(args->namelen);
189 xfs_idata_realloc(dp, size, XFS_DATA_FORK);
190 sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
191 sfe = (xfs_dir_sf_entry_t *)((char *)sf + offset);
192
193 XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sfe->inumber);
194 sfe->namelen = args->namelen;
195 memcpy(sfe->name, args->name, sfe->namelen);
Nathan Scottb2fc6ad2006-03-17 17:30:01 +1100196 sf->hdr.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 dp->i_d.di_size += size;
199 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
200
Jesper Juhl014c2542006-01-15 02:37:08 +0100201 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
204/*
205 * Remove a name from the shortform directory structure.
206 */
207int
208xfs_dir_shortform_removename(xfs_da_args_t *args)
209{
210 xfs_dir_shortform_t *sf;
211 xfs_dir_sf_entry_t *sfe;
212 int base, size = 0, i;
213 xfs_inode_t *dp;
214
215 dp = args->dp;
216 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
217 /*
218 * Catch the case where the conversion from shortform to leaf
219 * failed part way through.
220 */
221 if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
222 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
223 return XFS_ERROR(EIO);
224 }
225 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
226 ASSERT(dp->i_df.if_u1.if_data != NULL);
227 base = sizeof(xfs_dir_sf_hdr_t);
228 sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
229 sfe = &sf->list[0];
Nathan Scottb2fc6ad2006-03-17 17:30:01 +1100230 for (i = sf->hdr.count-1; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 size = XFS_DIR_SF_ENTSIZE_BYENTRY(sfe);
232 if (sfe->namelen == args->namelen &&
233 sfe->name[0] == args->name[0] &&
234 memcmp(sfe->name, args->name, args->namelen) == 0)
235 break;
236 base += size;
237 sfe = XFS_DIR_SF_NEXTENTRY(sfe);
238 }
239 if (i < 0) {
240 ASSERT(args->oknoent);
Jesper Juhl014c2542006-01-15 02:37:08 +0100241 return XFS_ERROR(ENOENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 }
243
244 if ((base + size) != dp->i_d.di_size) {
245 memmove(&((char *)sf)[base], &((char *)sf)[base+size],
246 dp->i_d.di_size - (base+size));
247 }
Nathan Scottb2fc6ad2006-03-17 17:30:01 +1100248 sf->hdr.count--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 xfs_idata_realloc(dp, -size, XFS_DATA_FORK);
251 dp->i_d.di_size -= size;
252 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
253
Jesper Juhl014c2542006-01-15 02:37:08 +0100254 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255}
256
257/*
258 * Look up a name in a shortform directory structure.
259 */
260int
261xfs_dir_shortform_lookup(xfs_da_args_t *args)
262{
263 xfs_dir_shortform_t *sf;
264 xfs_dir_sf_entry_t *sfe;
265 int i;
266 xfs_inode_t *dp;
267
268 dp = args->dp;
269 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
270 /*
271 * Catch the case where the conversion from shortform to leaf
272 * failed part way through.
273 */
274 if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
275 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
276 return XFS_ERROR(EIO);
277 }
278 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
279 ASSERT(dp->i_df.if_u1.if_data != NULL);
280 sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
281 if (args->namelen == 2 &&
282 args->name[0] == '.' && args->name[1] == '.') {
283 XFS_DIR_SF_GET_DIRINO(&sf->hdr.parent, &args->inumber);
284 return(XFS_ERROR(EEXIST));
285 }
286 if (args->namelen == 1 && args->name[0] == '.') {
287 args->inumber = dp->i_ino;
288 return(XFS_ERROR(EEXIST));
289 }
290 sfe = &sf->list[0];
Nathan Scottb2fc6ad2006-03-17 17:30:01 +1100291 for (i = sf->hdr.count-1; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 if (sfe->namelen == args->namelen &&
293 sfe->name[0] == args->name[0] &&
294 memcmp(args->name, sfe->name, args->namelen) == 0) {
295 XFS_DIR_SF_GET_DIRINO(&sfe->inumber, &args->inumber);
296 return(XFS_ERROR(EEXIST));
297 }
298 sfe = XFS_DIR_SF_NEXTENTRY(sfe);
299 }
300 ASSERT(args->oknoent);
301 return(XFS_ERROR(ENOENT));
302}
303
304/*
305 * Convert from using the shortform to the leaf.
306 */
307int
308xfs_dir_shortform_to_leaf(xfs_da_args_t *iargs)
309{
310 xfs_inode_t *dp;
311 xfs_dir_shortform_t *sf;
312 xfs_dir_sf_entry_t *sfe;
313 xfs_da_args_t args;
314 xfs_ino_t inumber;
315 char *tmpbuffer;
316 int retval, i, size;
317 xfs_dablk_t blkno;
318 xfs_dabuf_t *bp;
319
320 dp = iargs->dp;
321 /*
322 * Catch the case where the conversion from shortform to leaf
323 * failed part way through.
324 */
325 if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
326 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
327 return XFS_ERROR(EIO);
328 }
329 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
330 ASSERT(dp->i_df.if_u1.if_data != NULL);
331 size = dp->i_df.if_bytes;
332 tmpbuffer = kmem_alloc(size, KM_SLEEP);
333 ASSERT(tmpbuffer != NULL);
334
335 memcpy(tmpbuffer, dp->i_df.if_u1.if_data, size);
336
337 sf = (xfs_dir_shortform_t *)tmpbuffer;
338 XFS_DIR_SF_GET_DIRINO(&sf->hdr.parent, &inumber);
339
340 xfs_idata_realloc(dp, -size, XFS_DATA_FORK);
341 dp->i_d.di_size = 0;
342 xfs_trans_log_inode(iargs->trans, dp, XFS_ILOG_CORE);
343 retval = xfs_da_grow_inode(iargs, &blkno);
344 if (retval)
345 goto out;
346
347 ASSERT(blkno == 0);
348 retval = xfs_dir_leaf_create(iargs, blkno, &bp);
349 if (retval)
350 goto out;
351 xfs_da_buf_done(bp);
352
353 args.name = ".";
354 args.namelen = 1;
355 args.hashval = xfs_dir_hash_dot;
356 args.inumber = dp->i_ino;
357 args.dp = dp;
358 args.firstblock = iargs->firstblock;
359 args.flist = iargs->flist;
360 args.total = iargs->total;
361 args.whichfork = XFS_DATA_FORK;
362 args.trans = iargs->trans;
363 args.justcheck = 0;
364 args.addname = args.oknoent = 1;
365 retval = xfs_dir_leaf_addname(&args);
366 if (retval)
367 goto out;
368
369 args.name = "..";
370 args.namelen = 2;
371 args.hashval = xfs_dir_hash_dotdot;
372 args.inumber = inumber;
373 retval = xfs_dir_leaf_addname(&args);
374 if (retval)
375 goto out;
376
377 sfe = &sf->list[0];
Nathan Scottb2fc6ad2006-03-17 17:30:01 +1100378 for (i = 0; i < sf->hdr.count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 args.name = (char *)(sfe->name);
380 args.namelen = sfe->namelen;
381 args.hashval = xfs_da_hashname((char *)(sfe->name),
382 sfe->namelen);
383 XFS_DIR_SF_GET_DIRINO(&sfe->inumber, &args.inumber);
384 retval = xfs_dir_leaf_addname(&args);
385 if (retval)
386 goto out;
387 sfe = XFS_DIR_SF_NEXTENTRY(sfe);
388 }
389 retval = 0;
390
391out:
392 kmem_free(tmpbuffer, size);
Jesper Juhl014c2542006-01-15 02:37:08 +0100393 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394}
395
396STATIC int
397xfs_dir_shortform_compare(const void *a, const void *b)
398{
399 xfs_dir_sf_sort_t *sa, *sb;
400
401 sa = (xfs_dir_sf_sort_t *)a;
402 sb = (xfs_dir_sf_sort_t *)b;
403 if (sa->hash < sb->hash)
404 return -1;
405 else if (sa->hash > sb->hash)
406 return 1;
407 else
408 return sa->entno - sb->entno;
409}
410
411/*
412 * Copy out directory entries for getdents(), for shortform directories.
413 */
414/*ARGSUSED*/
415int
416xfs_dir_shortform_getdents(xfs_inode_t *dp, uio_t *uio, int *eofp,
417 xfs_dirent_t *dbp, xfs_dir_put_t put)
418{
419 xfs_dir_shortform_t *sf;
420 xfs_dir_sf_entry_t *sfe;
421 int retval, i, sbsize, nsbuf, lastresid=0, want_entno;
422 xfs_mount_t *mp;
423 xfs_dahash_t cookhash, hash;
424 xfs_dir_put_args_t p;
425 xfs_dir_sf_sort_t *sbuf, *sbp;
426
427 mp = dp->i_mount;
428 sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
429 cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset);
430 want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset);
Nathan Scottb2fc6ad2006-03-17 17:30:01 +1100431 nsbuf = sf->hdr.count + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 sbsize = (nsbuf + 1) * sizeof(*sbuf);
433 sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP);
434
435 xfs_dir_trace_g_du("sf: start", dp, uio);
436
437 /*
438 * Collect all the entries into the buffer.
439 * Entry 0 is .
440 */
441 sbp->entno = 0;
442 sbp->seqno = 0;
443 sbp->hash = xfs_dir_hash_dot;
444 sbp->ino = dp->i_ino;
445 sbp->name = ".";
446 sbp->namelen = 1;
447 sbp++;
448
449 /*
450 * Entry 1 is ..
451 */
452 sbp->entno = 1;
453 sbp->seqno = 0;
454 sbp->hash = xfs_dir_hash_dotdot;
455 sbp->ino = XFS_GET_DIR_INO8(sf->hdr.parent);
456 sbp->name = "..";
457 sbp->namelen = 2;
458 sbp++;
459
460 /*
461 * Scan the directory data for the rest of the entries.
462 */
Nathan Scottb2fc6ad2006-03-17 17:30:01 +1100463 for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 if (unlikely(
466 ((char *)sfe < (char *)sf) ||
467 ((char *)sfe >= ((char *)sf + dp->i_df.if_bytes)))) {
468 xfs_dir_trace_g_du("sf: corrupted", dp, uio);
469 XFS_CORRUPTION_ERROR("xfs_dir_shortform_getdents",
470 XFS_ERRLEVEL_LOW, mp, sfe);
471 kmem_free(sbuf, sbsize);
472 return XFS_ERROR(EFSCORRUPTED);
473 }
474
475 sbp->entno = i + 2;
476 sbp->seqno = 0;
477 sbp->hash = xfs_da_hashname((char *)sfe->name, sfe->namelen);
478 sbp->ino = XFS_GET_DIR_INO8(sfe->inumber);
479 sbp->name = (char *)sfe->name;
480 sbp->namelen = sfe->namelen;
481 sfe = XFS_DIR_SF_NEXTENTRY(sfe);
482 sbp++;
483 }
484
485 /*
486 * Sort the entries on hash then entno.
487 */
Nathan Scott380b5dc2005-11-02 11:43:18 +1100488 xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_dir_shortform_compare);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 /*
490 * Stuff in last entry.
491 */
492 sbp->entno = nsbuf;
493 sbp->hash = XFS_DA_MAXHASH;
494 sbp->seqno = 0;
495 /*
496 * Figure out the sequence numbers in case there's a hash duplicate.
497 */
498 for (hash = sbuf->hash, sbp = sbuf + 1;
499 sbp < &sbuf[nsbuf + 1]; sbp++) {
500 if (sbp->hash == hash)
501 sbp->seqno = sbp[-1].seqno + 1;
502 else
503 hash = sbp->hash;
504 }
505
506 /*
507 * Set up put routine.
508 */
509 p.dbp = dbp;
510 p.put = put;
511 p.uio = uio;
512
513 /*
514 * Find our place.
515 */
516 for (sbp = sbuf; sbp < &sbuf[nsbuf + 1]; sbp++) {
517 if (sbp->hash > cookhash ||
518 (sbp->hash == cookhash && sbp->seqno >= want_entno))
519 break;
520 }
521
522 /*
523 * Did we fail to find anything? We stop at the last entry,
524 * the one we put maxhash into.
525 */
526 if (sbp == &sbuf[nsbuf]) {
527 kmem_free(sbuf, sbsize);
528 xfs_dir_trace_g_du("sf: hash beyond end", dp, uio);
529 uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH);
530 *eofp = 1;
531 return 0;
532 }
533
534 /*
535 * Loop putting entries into the user buffer.
536 */
537 while (sbp < &sbuf[nsbuf]) {
538 /*
539 * Save the first resid in a run of equal-hashval entries
540 * so that we can back them out if they don't all fit.
541 */
542 if (sbp->seqno == 0 || sbp == sbuf)
543 lastresid = uio->uio_resid;
544 XFS_PUT_COOKIE(p.cook, mp, 0, sbp[1].seqno, sbp[1].hash);
545 p.ino = sbp->ino;
546#if XFS_BIG_INUMS
547 p.ino += mp->m_inoadd;
548#endif
549 p.name = sbp->name;
550 p.namelen = sbp->namelen;
551 retval = p.put(&p);
552 if (!p.done) {
553 uio->uio_offset =
554 XFS_DA_MAKE_COOKIE(mp, 0, 0, sbp->hash);
555 kmem_free(sbuf, sbsize);
556 uio->uio_resid = lastresid;
557 xfs_dir_trace_g_du("sf: E-O-B", dp, uio);
558 return retval;
559 }
560 sbp++;
561 }
562 kmem_free(sbuf, sbsize);
563 uio->uio_offset = p.cook.o;
564 *eofp = 1;
565 xfs_dir_trace_g_du("sf: E-O-F", dp, uio);
566 return 0;
567}
568
569/*
570 * Look up a name in a shortform directory structure, replace the inode number.
571 */
572int
573xfs_dir_shortform_replace(xfs_da_args_t *args)
574{
575 xfs_dir_shortform_t *sf;
576 xfs_dir_sf_entry_t *sfe;
577 xfs_inode_t *dp;
578 int i;
579
580 dp = args->dp;
581 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
582 /*
583 * Catch the case where the conversion from shortform to leaf
584 * failed part way through.
585 */
586 if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
587 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
588 return XFS_ERROR(EIO);
589 }
590 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
591 ASSERT(dp->i_df.if_u1.if_data != NULL);
592 sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
593 if (args->namelen == 2 &&
594 args->name[0] == '.' && args->name[1] == '.') {
595 /* XXX - replace assert? */
596 XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sf->hdr.parent);
597 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
Jesper Juhl014c2542006-01-15 02:37:08 +0100598 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 }
600 ASSERT(args->namelen != 1 || args->name[0] != '.');
601 sfe = &sf->list[0];
Nathan Scottb2fc6ad2006-03-17 17:30:01 +1100602 for (i = sf->hdr.count-1; i >= 0; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 if (sfe->namelen == args->namelen &&
604 sfe->name[0] == args->name[0] &&
605 memcmp(args->name, sfe->name, args->namelen) == 0) {
606 ASSERT(memcmp((char *)&args->inumber,
607 (char *)&sfe->inumber, sizeof(xfs_ino_t)));
608 XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sfe->inumber);
609 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
Jesper Juhl014c2542006-01-15 02:37:08 +0100610 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 }
612 sfe = XFS_DIR_SF_NEXTENTRY(sfe);
613 }
614 ASSERT(args->oknoent);
Jesper Juhl014c2542006-01-15 02:37:08 +0100615 return XFS_ERROR(ENOENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616}
617
618/*
619 * Convert a leaf directory to shortform structure
620 */
621int
622xfs_dir_leaf_to_shortform(xfs_da_args_t *iargs)
623{
624 xfs_dir_leafblock_t *leaf;
625 xfs_dir_leaf_hdr_t *hdr;
626 xfs_dir_leaf_entry_t *entry;
627 xfs_dir_leaf_name_t *namest;
628 xfs_da_args_t args;
629 xfs_inode_t *dp;
Christoph Hellwig5bde1ba2005-11-02 15:06:18 +1100630 xfs_ino_t parent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 char *tmpbuffer;
632 int retval, i;
633 xfs_dabuf_t *bp;
634
635 dp = iargs->dp;
636 tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP);
637 ASSERT(tmpbuffer != NULL);
638
639 retval = xfs_da_read_buf(iargs->trans, iargs->dp, 0, -1, &bp,
640 XFS_DATA_FORK);
641 if (retval)
642 goto out;
643 ASSERT(bp != NULL);
644 memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
645 leaf = (xfs_dir_leafblock_t *)tmpbuffer;
Nathan Scott89da0542006-03-17 17:28:40 +1100646 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
648
649 /*
650 * Find and special case the parent inode number
651 */
652 hdr = &leaf->hdr;
653 entry = &leaf->entries[0];
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000654 for (i = be16_to_cpu(hdr->count)-1; i >= 0; entry++, i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
656 if ((entry->namelen == 2) &&
657 (namest->name[0] == '.') &&
658 (namest->name[1] == '.')) {
659 XFS_DIR_SF_GET_DIRINO(&namest->inumber, &parent);
660 entry->nameidx = 0;
661 } else if ((entry->namelen == 1) && (namest->name[0] == '.')) {
662 entry->nameidx = 0;
663 }
664 }
665 retval = xfs_da_shrink_inode(iargs, 0, bp);
666 if (retval)
667 goto out;
668 retval = xfs_dir_shortform_create(iargs, parent);
669 if (retval)
670 goto out;
671
672 /*
673 * Copy the rest of the filenames
674 */
675 entry = &leaf->entries[0];
676 args.dp = dp;
677 args.firstblock = iargs->firstblock;
678 args.flist = iargs->flist;
679 args.total = iargs->total;
680 args.whichfork = XFS_DATA_FORK;
681 args.trans = iargs->trans;
682 args.justcheck = 0;
683 args.addname = args.oknoent = 1;
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000684 for (i = 0; i < be16_to_cpu(hdr->count); entry++, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (!entry->nameidx)
686 continue;
687 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
688 args.name = (char *)(namest->name);
689 args.namelen = entry->namelen;
690 args.hashval = INT_GET(entry->hashval, ARCH_CONVERT);
691 XFS_DIR_SF_GET_DIRINO(&namest->inumber, &args.inumber);
692 xfs_dir_shortform_addname(&args);
693 }
694
695out:
696 kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount));
Jesper Juhl014c2542006-01-15 02:37:08 +0100697 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698}
699
700/*
701 * Convert from using a single leaf to a root node and a leaf.
702 */
703int
704xfs_dir_leaf_to_node(xfs_da_args_t *args)
705{
706 xfs_dir_leafblock_t *leaf;
707 xfs_da_intnode_t *node;
708 xfs_inode_t *dp;
709 xfs_dabuf_t *bp1, *bp2;
710 xfs_dablk_t blkno;
711 int retval;
712
713 dp = args->dp;
714 retval = xfs_da_grow_inode(args, &blkno);
715 ASSERT(blkno == 1);
716 if (retval)
Jesper Juhl014c2542006-01-15 02:37:08 +0100717 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1,
719 XFS_DATA_FORK);
720 if (retval)
Jesper Juhl014c2542006-01-15 02:37:08 +0100721 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 ASSERT(bp1 != NULL);
723 retval = xfs_da_get_buf(args->trans, args->dp, 1, -1, &bp2,
724 XFS_DATA_FORK);
725 if (retval) {
726 xfs_da_buf_done(bp1);
Jesper Juhl014c2542006-01-15 02:37:08 +0100727 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 }
729 ASSERT(bp2 != NULL);
730 memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount));
731 xfs_da_buf_done(bp1);
732 xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
733
734 /*
735 * Set up the new root node.
736 */
737 retval = xfs_da_node_create(args, 0, 1, &bp1, XFS_DATA_FORK);
738 if (retval) {
739 xfs_da_buf_done(bp2);
Jesper Juhl014c2542006-01-15 02:37:08 +0100740 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 }
742 node = bp1->data;
743 leaf = bp2->data;
Nathan Scott89da0542006-03-17 17:28:40 +1100744 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Nathan Scottfac80cc2006-03-17 17:29:56 +1100745 node->btree[0].hashval = cpu_to_be32(
746 INT_GET(leaf->entries[
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000747 be16_to_cpu(leaf->hdr.count)-1].hashval, ARCH_CONVERT));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 xfs_da_buf_done(bp2);
Nathan Scott403432d2006-03-17 17:29:46 +1100749 node->btree[0].before = cpu_to_be32(blkno);
Nathan Scottfac80cc2006-03-17 17:29:56 +1100750 node->hdr.count = cpu_to_be16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 xfs_da_log_buf(args->trans, bp1,
752 XFS_DA_LOGRANGE(node, &node->btree[0], sizeof(node->btree[0])));
753 xfs_da_buf_done(bp1);
754
Jesper Juhl014c2542006-01-15 02:37:08 +0100755 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756}
757
758
759/*========================================================================
760 * Routines used for growing the Btree.
761 *========================================================================*/
762
763/*
764 * Create the initial contents of a leaf directory
765 * or a leaf in a node directory.
766 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +1000767STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
769{
770 xfs_dir_leafblock_t *leaf;
771 xfs_dir_leaf_hdr_t *hdr;
772 xfs_inode_t *dp;
773 xfs_dabuf_t *bp;
774 int retval;
775
776 dp = args->dp;
777 ASSERT(dp != NULL);
778 retval = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp, XFS_DATA_FORK);
779 if (retval)
Jesper Juhl014c2542006-01-15 02:37:08 +0100780 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 ASSERT(bp != NULL);
782 leaf = bp->data;
783 memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
784 hdr = &leaf->hdr;
Nathan Scott89da0542006-03-17 17:28:40 +1100785 hdr->info.magic = cpu_to_be16(XFS_DIR_LEAF_MAGIC);
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000786 hdr->firstused = cpu_to_be16(XFS_LBSIZE(dp->i_mount));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 if (!hdr->firstused)
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000788 hdr->firstused = cpu_to_be16(XFS_LBSIZE(dp->i_mount) - 1);
789 hdr->freemap[0].base = cpu_to_be16(sizeof(xfs_dir_leaf_hdr_t));
790 hdr->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr->firstused) -
791 be16_to_cpu(hdr->freemap[0].base));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793 xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1);
794
795 *bpp = bp;
Jesper Juhl014c2542006-01-15 02:37:08 +0100796 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797}
798
799/*
800 * Split the leaf node, rebalance, then add the new entry.
801 */
802int
803xfs_dir_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
804 xfs_da_state_blk_t *newblk)
805{
806 xfs_dablk_t blkno;
807 xfs_da_args_t *args;
808 int error;
809
810 /*
811 * Allocate space for a new leaf node.
812 */
813 args = state->args;
814 ASSERT(args != NULL);
815 ASSERT(oldblk->magic == XFS_DIR_LEAF_MAGIC);
816 error = xfs_da_grow_inode(args, &blkno);
817 if (error)
Jesper Juhl014c2542006-01-15 02:37:08 +0100818 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 error = xfs_dir_leaf_create(args, blkno, &newblk->bp);
820 if (error)
Jesper Juhl014c2542006-01-15 02:37:08 +0100821 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 newblk->blkno = blkno;
823 newblk->magic = XFS_DIR_LEAF_MAGIC;
824
825 /*
826 * Rebalance the entries across the two leaves.
827 */
828 xfs_dir_leaf_rebalance(state, oldblk, newblk);
829 error = xfs_da_blk_link(state, oldblk, newblk);
830 if (error)
Jesper Juhl014c2542006-01-15 02:37:08 +0100831 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 /*
834 * Insert the new entry in the correct block.
835 */
836 if (state->inleaf) {
837 error = xfs_dir_leaf_add(oldblk->bp, args, oldblk->index);
838 } else {
839 error = xfs_dir_leaf_add(newblk->bp, args, newblk->index);
840 }
841
842 /*
843 * Update last hashval in each block since we added the name.
844 */
845 oldblk->hashval = xfs_dir_leaf_lasthash(oldblk->bp, NULL);
846 newblk->hashval = xfs_dir_leaf_lasthash(newblk->bp, NULL);
Jesper Juhl014c2542006-01-15 02:37:08 +0100847 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848}
849
850/*
851 * Add a name to the leaf directory structure.
852 *
853 * Must take into account fragmented leaves and leaves where spacemap has
854 * lost some freespace information (ie: holes).
855 */
856int
857xfs_dir_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index)
858{
859 xfs_dir_leafblock_t *leaf;
860 xfs_dir_leaf_hdr_t *hdr;
861 xfs_dir_leaf_map_t *map;
862 int tablesize, entsize, sum, i, tmp, error;
863
864 leaf = bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +1100865 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000866 ASSERT((index >= 0) && (index <= be16_to_cpu(leaf->hdr.count)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 hdr = &leaf->hdr;
868 entsize = XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen);
869
870 /*
871 * Search through freemap for first-fit on new name length.
872 * (may need to figure in size of entry struct too)
873 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000874 tablesize = (be16_to_cpu(hdr->count) + 1) *
875 sizeof(xfs_dir_leaf_entry_t) + sizeof(xfs_dir_leaf_hdr_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 map = &hdr->freemap[XFS_DIR_LEAF_MAPSIZE-1];
877 for (sum = 0, i = XFS_DIR_LEAF_MAPSIZE-1; i >= 0; map--, i--) {
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000878 if (tablesize > be16_to_cpu(hdr->firstused)) {
879 sum += be16_to_cpu(map->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 continue;
881 }
882 if (!map->size)
883 continue; /* no space in this map */
884 tmp = entsize;
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000885 if (be16_to_cpu(map->base) < be16_to_cpu(hdr->firstused))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 tmp += (uint)sizeof(xfs_dir_leaf_entry_t);
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000887 if (be16_to_cpu(map->size) >= tmp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 if (!args->justcheck)
889 xfs_dir_leaf_add_work(bp, args, index, i);
Jesper Juhl014c2542006-01-15 02:37:08 +0100890 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 }
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000892 sum += be16_to_cpu(map->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 }
894
895 /*
896 * If there are no holes in the address space of the block,
897 * and we don't have enough freespace, then compaction will do us
898 * no good and we should just give up.
899 */
900 if (!hdr->holes && (sum < entsize))
Jesper Juhl014c2542006-01-15 02:37:08 +0100901 return XFS_ERROR(ENOSPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
903 /*
904 * Compact the entries to coalesce free space.
905 * Pass the justcheck flag so the checking pass can return
906 * an error, without changing anything, if it won't fit.
907 */
908 error = xfs_dir_leaf_compact(args->trans, bp,
909 args->total == 0 ?
910 entsize +
911 (uint)sizeof(xfs_dir_leaf_entry_t) : 0,
912 args->justcheck);
913 if (error)
Jesper Juhl014c2542006-01-15 02:37:08 +0100914 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 /*
916 * After compaction, the block is guaranteed to have only one
917 * free region, in freemap[0]. If it is not big enough, give up.
918 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000919 if (be16_to_cpu(hdr->freemap[0].size) <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 (entsize + (uint)sizeof(xfs_dir_leaf_entry_t)))
Jesper Juhl014c2542006-01-15 02:37:08 +0100921 return XFS_ERROR(ENOSPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923 if (!args->justcheck)
924 xfs_dir_leaf_add_work(bp, args, index, 0);
Jesper Juhl014c2542006-01-15 02:37:08 +0100925 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926}
927
928/*
929 * Add a name to a leaf directory structure.
930 */
931STATIC void
932xfs_dir_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int index,
933 int mapindex)
934{
935 xfs_dir_leafblock_t *leaf;
936 xfs_dir_leaf_hdr_t *hdr;
937 xfs_dir_leaf_entry_t *entry;
938 xfs_dir_leaf_name_t *namest;
939 xfs_dir_leaf_map_t *map;
940 /* REFERENCED */
941 xfs_mount_t *mp;
942 int tmp, i;
943
944 leaf = bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +1100945 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 hdr = &leaf->hdr;
947 ASSERT((mapindex >= 0) && (mapindex < XFS_DIR_LEAF_MAPSIZE));
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000948 ASSERT((index >= 0) && (index <= be16_to_cpu(hdr->count)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950 /*
951 * Force open some space in the entry array and fill it in.
952 */
953 entry = &leaf->entries[index];
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000954 if (index < be16_to_cpu(hdr->count)) {
955 tmp = be16_to_cpu(hdr->count) - index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
957 memmove(entry + 1, entry, tmp);
958 xfs_da_log_buf(args->trans, bp,
959 XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
960 }
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000961 be16_add(&hdr->count, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 /*
964 * Allocate space for the new string (at the end of the run).
965 */
966 map = &hdr->freemap[mapindex];
967 mp = args->trans->t_mountp;
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000968 ASSERT(be16_to_cpu(map->base) < XFS_LBSIZE(mp));
969 ASSERT(be16_to_cpu(map->size) >= XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen));
970 ASSERT(be16_to_cpu(map->size) < XFS_LBSIZE(mp));
971
972 be16_add(&map->size, -(XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen)));
973 INT_SET(entry->nameidx, ARCH_CONVERT, be16_to_cpu(map->base) + be16_to_cpu(map->size));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 INT_SET(entry->hashval, ARCH_CONVERT, args->hashval);
975 entry->namelen = args->namelen;
976 xfs_da_log_buf(args->trans, bp,
977 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
978
979 /*
980 * Copy the string and inode number into the new space.
981 */
982 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
983 XFS_DIR_SF_PUT_DIRINO(&args->inumber, &namest->inumber);
984 memcpy(namest->name, args->name, args->namelen);
985 xfs_da_log_buf(args->trans, bp,
986 XFS_DA_LOGRANGE(leaf, namest, XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry)));
987
988 /*
989 * Update the control info for this leaf node
990 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000991 if (INT_GET(entry->nameidx, ARCH_CONVERT) < be16_to_cpu(hdr->firstused))
992 hdr->firstused = entry->nameidx;
993 ASSERT(be16_to_cpu(hdr->firstused) >=
994 ((be16_to_cpu(hdr->count)*sizeof(*entry))+sizeof(*hdr)));
995 tmp = (be16_to_cpu(hdr->count)-1) * (uint)sizeof(xfs_dir_leaf_entry_t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 + (uint)sizeof(xfs_dir_leaf_hdr_t);
997 map = &hdr->freemap[0];
998 for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) {
Christoph Hellwig8034fff2006-06-09 14:50:24 +1000999 if (be16_to_cpu(map->base) == tmp) {
1000 int entry_size = sizeof(xfs_dir_leaf_entry_t);
1001 be16_add(&map->base, entry_size);
1002 be16_add(&map->size, -entry_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
1004 }
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001005 be16_add(&hdr->namebytes, args->namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 xfs_da_log_buf(args->trans, bp,
1007 XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
1008}
1009
1010/*
1011 * Garbage collect a leaf directory block by copying it to a new buffer.
1012 */
1013STATIC int
1014xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp, int musthave,
1015 int justcheck)
1016{
1017 xfs_dir_leafblock_t *leaf_s, *leaf_d;
1018 xfs_dir_leaf_hdr_t *hdr_s, *hdr_d;
1019 xfs_mount_t *mp;
1020 char *tmpbuffer;
1021 char *tmpbuffer2=NULL;
1022 int rval;
1023 int lbsize;
1024
1025 mp = trans->t_mountp;
1026 lbsize = XFS_LBSIZE(mp);
1027 tmpbuffer = kmem_alloc(lbsize, KM_SLEEP);
1028 ASSERT(tmpbuffer != NULL);
1029 memcpy(tmpbuffer, bp->data, lbsize);
1030
1031 /*
1032 * Make a second copy in case xfs_dir_leaf_moveents()
1033 * below destroys the original.
1034 */
1035 if (musthave || justcheck) {
1036 tmpbuffer2 = kmem_alloc(lbsize, KM_SLEEP);
1037 memcpy(tmpbuffer2, bp->data, lbsize);
1038 }
1039 memset(bp->data, 0, lbsize);
1040
1041 /*
1042 * Copy basic information
1043 */
1044 leaf_s = (xfs_dir_leafblock_t *)tmpbuffer;
1045 leaf_d = bp->data;
1046 hdr_s = &leaf_s->hdr;
1047 hdr_d = &leaf_d->hdr;
1048 hdr_d->info = hdr_s->info; /* struct copy */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001049 hdr_d->firstused = cpu_to_be16(lbsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 if (!hdr_d->firstused)
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001051 hdr_d->firstused = cpu_to_be16(lbsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 hdr_d->namebytes = 0;
1053 hdr_d->count = 0;
1054 hdr_d->holes = 0;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001055 hdr_d->freemap[0].base = cpu_to_be16(sizeof(xfs_dir_leaf_hdr_t));
1056 hdr_d->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr_d->firstused) -
1057 be16_to_cpu(hdr_d->freemap[0].base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
1059 /*
1060 * Copy all entry's in the same (sorted) order,
1061 * but allocate filenames packed and in sequence.
1062 * This changes the source (leaf_s) as well.
1063 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001064 xfs_dir_leaf_moveents(leaf_s, 0, leaf_d, 0, be16_to_cpu(hdr_s->count), mp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001066 if (musthave && be16_to_cpu(hdr_d->freemap[0].size) < musthave)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 rval = XFS_ERROR(ENOSPC);
1068 else
1069 rval = 0;
1070
1071 if (justcheck || rval == ENOSPC) {
1072 ASSERT(tmpbuffer2);
1073 memcpy(bp->data, tmpbuffer2, lbsize);
1074 } else {
1075 xfs_da_log_buf(trans, bp, 0, lbsize - 1);
1076 }
1077
1078 kmem_free(tmpbuffer, lbsize);
1079 if (musthave || justcheck)
1080 kmem_free(tmpbuffer2, lbsize);
Jesper Juhl014c2542006-01-15 02:37:08 +01001081 return rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082}
1083
1084/*
1085 * Redistribute the directory entries between two leaf nodes,
1086 * taking into account the size of the new entry.
1087 *
1088 * NOTE: if new block is empty, then it will get the upper half of old block.
1089 */
1090STATIC void
1091xfs_dir_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
1092 xfs_da_state_blk_t *blk2)
1093{
1094 xfs_da_state_blk_t *tmp_blk;
1095 xfs_dir_leafblock_t *leaf1, *leaf2;
1096 xfs_dir_leaf_hdr_t *hdr1, *hdr2;
1097 int count, totallen, max, space, swap;
1098
1099 /*
1100 * Set up environment.
1101 */
1102 ASSERT(blk1->magic == XFS_DIR_LEAF_MAGIC);
1103 ASSERT(blk2->magic == XFS_DIR_LEAF_MAGIC);
1104 leaf1 = blk1->bp->data;
1105 leaf2 = blk2->bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +11001106 ASSERT(be16_to_cpu(leaf1->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
1107 ASSERT(be16_to_cpu(leaf2->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
1109 /*
1110 * Check ordering of blocks, reverse if it makes things simpler.
1111 */
1112 swap = 0;
1113 if (xfs_dir_leaf_order(blk1->bp, blk2->bp)) {
1114 tmp_blk = blk1;
1115 blk1 = blk2;
1116 blk2 = tmp_blk;
1117 leaf1 = blk1->bp->data;
1118 leaf2 = blk2->bp->data;
1119 swap = 1;
1120 }
1121 hdr1 = &leaf1->hdr;
1122 hdr2 = &leaf2->hdr;
1123
1124 /*
1125 * Examine entries until we reduce the absolute difference in
1126 * byte usage between the two blocks to a minimum. Then get
1127 * the direction to copy and the number of elements to move.
1128 */
1129 state->inleaf = xfs_dir_leaf_figure_balance(state, blk1, blk2,
1130 &count, &totallen);
1131 if (swap)
1132 state->inleaf = !state->inleaf;
1133
1134 /*
1135 * Move any entries required from leaf to leaf:
1136 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001137 if (count < be16_to_cpu(hdr1->count)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 /*
1139 * Figure the total bytes to be added to the destination leaf.
1140 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001141 count = be16_to_cpu(hdr1->count) - count; /* number entries being moved */
1142 space = be16_to_cpu(hdr1->namebytes) - totallen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1);
1144 space += count * (uint)sizeof(xfs_dir_leaf_entry_t);
1145
1146 /*
1147 * leaf2 is the destination, compact it if it looks tight.
1148 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001149 max = be16_to_cpu(hdr2->firstused) - (uint)sizeof(xfs_dir_leaf_hdr_t);
1150 max -= be16_to_cpu(hdr2->count) * (uint)sizeof(xfs_dir_leaf_entry_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 if (space > max) {
1152 xfs_dir_leaf_compact(state->args->trans, blk2->bp,
1153 0, 0);
1154 }
1155
1156 /*
1157 * Move high entries from leaf1 to low end of leaf2.
1158 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001159 xfs_dir_leaf_moveents(leaf1, be16_to_cpu(hdr1->count) - count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 leaf2, 0, count, state->mp);
1161
1162 xfs_da_log_buf(state->args->trans, blk1->bp, 0,
1163 state->blocksize-1);
1164 xfs_da_log_buf(state->args->trans, blk2->bp, 0,
1165 state->blocksize-1);
1166
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001167 } else if (count > be16_to_cpu(hdr1->count)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 /*
1169 * Figure the total bytes to be added to the destination leaf.
1170 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001171 count -= be16_to_cpu(hdr1->count); /* number entries being moved */
1172 space = totallen - be16_to_cpu(hdr1->namebytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1);
1174 space += count * (uint)sizeof(xfs_dir_leaf_entry_t);
1175
1176 /*
1177 * leaf1 is the destination, compact it if it looks tight.
1178 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001179 max = be16_to_cpu(hdr1->firstused) - (uint)sizeof(xfs_dir_leaf_hdr_t);
1180 max -= be16_to_cpu(hdr1->count) * (uint)sizeof(xfs_dir_leaf_entry_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 if (space > max) {
1182 xfs_dir_leaf_compact(state->args->trans, blk1->bp,
1183 0, 0);
1184 }
1185
1186 /*
1187 * Move low entries from leaf2 to high end of leaf1.
1188 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001189 xfs_dir_leaf_moveents(leaf2, 0, leaf1, be16_to_cpu(hdr1->count),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 count, state->mp);
1191
1192 xfs_da_log_buf(state->args->trans, blk1->bp, 0,
1193 state->blocksize-1);
1194 xfs_da_log_buf(state->args->trans, blk2->bp, 0,
1195 state->blocksize-1);
1196 }
1197
1198 /*
1199 * Copy out last hashval in each block for B-tree code.
1200 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001201 blk1->hashval = INT_GET(leaf1->entries[be16_to_cpu(leaf1->hdr.count)-1].hashval, ARCH_CONVERT);
1202 blk2->hashval = INT_GET(leaf2->entries[be16_to_cpu(leaf2->hdr.count)-1].hashval, ARCH_CONVERT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204 /*
1205 * Adjust the expected index for insertion.
1206 * GROT: this doesn't work unless blk2 was originally empty.
1207 */
1208 if (!state->inleaf) {
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001209 blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 }
1211}
1212
1213/*
1214 * Examine entries until we reduce the absolute difference in
1215 * byte usage between the two blocks to a minimum.
1216 * GROT: Is this really necessary? With other than a 512 byte blocksize,
1217 * GROT: there will always be enough room in either block for a new entry.
1218 * GROT: Do a double-split for this case?
1219 */
1220STATIC int
1221xfs_dir_leaf_figure_balance(xfs_da_state_t *state,
1222 xfs_da_state_blk_t *blk1,
1223 xfs_da_state_blk_t *blk2,
1224 int *countarg, int *namebytesarg)
1225{
1226 xfs_dir_leafblock_t *leaf1, *leaf2;
1227 xfs_dir_leaf_hdr_t *hdr1, *hdr2;
1228 xfs_dir_leaf_entry_t *entry;
1229 int count, max, totallen, half;
1230 int lastdelta, foundit, tmp;
1231
1232 /*
1233 * Set up environment.
1234 */
1235 leaf1 = blk1->bp->data;
1236 leaf2 = blk2->bp->data;
1237 hdr1 = &leaf1->hdr;
1238 hdr2 = &leaf2->hdr;
1239 foundit = 0;
1240 totallen = 0;
1241
1242 /*
1243 * Examine entries until we reduce the absolute difference in
1244 * byte usage between the two blocks to a minimum.
1245 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001246 max = be16_to_cpu(hdr1->count) + be16_to_cpu(hdr2->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 half = (max+1) * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001248 half += be16_to_cpu(hdr1->namebytes) + be16_to_cpu(hdr2->namebytes) +
1249 state->args->namelen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 half /= 2;
1251 lastdelta = state->blocksize;
1252 entry = &leaf1->entries[0];
1253 for (count = 0; count < max; entry++, count++) {
1254
1255#define XFS_DIR_ABS(A) (((A) < 0) ? -(A) : (A))
1256 /*
1257 * The new entry is in the first block, account for it.
1258 */
1259 if (count == blk1->index) {
1260 tmp = totallen + (uint)sizeof(*entry)
1261 + XFS_DIR_LEAF_ENTSIZE_BYNAME(state->args->namelen);
1262 if (XFS_DIR_ABS(half - tmp) > lastdelta)
1263 break;
1264 lastdelta = XFS_DIR_ABS(half - tmp);
1265 totallen = tmp;
1266 foundit = 1;
1267 }
1268
1269 /*
1270 * Wrap around into the second block if necessary.
1271 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001272 if (count == be16_to_cpu(hdr1->count)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 leaf1 = leaf2;
1274 entry = &leaf1->entries[0];
1275 }
1276
1277 /*
1278 * Figure out if next leaf entry would be too much.
1279 */
1280 tmp = totallen + (uint)sizeof(*entry)
1281 + XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry);
1282 if (XFS_DIR_ABS(half - tmp) > lastdelta)
1283 break;
1284 lastdelta = XFS_DIR_ABS(half - tmp);
1285 totallen = tmp;
1286#undef XFS_DIR_ABS
1287 }
1288
1289 /*
1290 * Calculate the number of namebytes that will end up in lower block.
1291 * If new entry not in lower block, fix up the count.
1292 */
1293 totallen -=
1294 count * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1);
1295 if (foundit) {
1296 totallen -= (sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1) +
1297 state->args->namelen;
1298 }
1299
1300 *countarg = count;
1301 *namebytesarg = totallen;
Jesper Juhl014c2542006-01-15 02:37:08 +01001302 return foundit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303}
1304
1305/*========================================================================
1306 * Routines used for shrinking the Btree.
1307 *========================================================================*/
1308
1309/*
1310 * Check a leaf block and its neighbors to see if the block should be
1311 * collapsed into one or the other neighbor. Always keep the block
1312 * with the smaller block number.
1313 * If the current block is over 50% full, don't try to join it, return 0.
1314 * If the block is empty, fill in the state structure and return 2.
1315 * If it can be collapsed, fill in the state structure and return 1.
1316 * If nothing can be done, return 0.
1317 */
1318int
1319xfs_dir_leaf_toosmall(xfs_da_state_t *state, int *action)
1320{
1321 xfs_dir_leafblock_t *leaf;
1322 xfs_da_state_blk_t *blk;
1323 xfs_da_blkinfo_t *info;
1324 int count, bytes, forward, error, retval, i;
1325 xfs_dablk_t blkno;
1326 xfs_dabuf_t *bp;
1327
1328 /*
1329 * Check for the degenerate case of the block being over 50% full.
1330 * If so, it's not worth even looking to see if we might be able
1331 * to coalesce with a sibling.
1332 */
1333 blk = &state->path.blk[ state->path.active-1 ];
1334 info = blk->bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +11001335 ASSERT(be16_to_cpu(info->magic) == XFS_DIR_LEAF_MAGIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 leaf = (xfs_dir_leafblock_t *)info;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001337 count = be16_to_cpu(leaf->hdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 bytes = (uint)sizeof(xfs_dir_leaf_hdr_t) +
1339 count * (uint)sizeof(xfs_dir_leaf_entry_t) +
1340 count * ((uint)sizeof(xfs_dir_leaf_name_t)-1) +
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001341 be16_to_cpu(leaf->hdr.namebytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 if (bytes > (state->blocksize >> 1)) {
1343 *action = 0; /* blk over 50%, don't try to join */
Jesper Juhl014c2542006-01-15 02:37:08 +01001344 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 }
1346
1347 /*
1348 * Check for the degenerate case of the block being empty.
1349 * If the block is empty, we'll simply delete it, no need to
Nathan Scottc41564b2006-03-29 08:55:14 +10001350 * coalesce it with a sibling block. We choose (arbitrarily)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 * to merge with the forward block unless it is NULL.
1352 */
1353 if (count == 0) {
1354 /*
1355 * Make altpath point to the block we want to keep and
1356 * path point to the block we want to drop (this one).
1357 */
Nathan Scott89da0542006-03-17 17:28:40 +11001358 forward = (info->forw != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 memcpy(&state->altpath, &state->path, sizeof(state->path));
1360 error = xfs_da_path_shift(state, &state->altpath, forward,
1361 0, &retval);
1362 if (error)
Jesper Juhl014c2542006-01-15 02:37:08 +01001363 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 if (retval) {
1365 *action = 0;
1366 } else {
1367 *action = 2;
1368 }
Jesper Juhl014c2542006-01-15 02:37:08 +01001369 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 }
1371
1372 /*
1373 * Examine each sibling block to see if we can coalesce with
1374 * at least 25% free space to spare. We need to figure out
1375 * whether to merge with the forward or the backward block.
1376 * We prefer coalescing with the lower numbered sibling so as
1377 * to shrink a directory over time.
1378 */
Nathan Scott89da0542006-03-17 17:28:40 +11001379 forward = (be32_to_cpu(info->forw) < be32_to_cpu(info->back)); /* start with smaller blk num */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 for (i = 0; i < 2; forward = !forward, i++) {
1381 if (forward)
Nathan Scott89da0542006-03-17 17:28:40 +11001382 blkno = be32_to_cpu(info->forw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 else
Nathan Scott89da0542006-03-17 17:28:40 +11001384 blkno = be32_to_cpu(info->back);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 if (blkno == 0)
1386 continue;
1387 error = xfs_da_read_buf(state->args->trans, state->args->dp,
1388 blkno, -1, &bp,
1389 XFS_DATA_FORK);
1390 if (error)
Jesper Juhl014c2542006-01-15 02:37:08 +01001391 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 ASSERT(bp != NULL);
1393
1394 leaf = (xfs_dir_leafblock_t *)info;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001395 count = be16_to_cpu(leaf->hdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 bytes = state->blocksize - (state->blocksize>>2);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001397 bytes -= be16_to_cpu(leaf->hdr.namebytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 leaf = bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +11001399 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001400 count += be16_to_cpu(leaf->hdr.count);
1401 bytes -= be16_to_cpu(leaf->hdr.namebytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 bytes -= count * ((uint)sizeof(xfs_dir_leaf_name_t) - 1);
1403 bytes -= count * (uint)sizeof(xfs_dir_leaf_entry_t);
1404 bytes -= (uint)sizeof(xfs_dir_leaf_hdr_t);
1405 if (bytes >= 0)
1406 break; /* fits with at least 25% to spare */
1407
1408 xfs_da_brelse(state->args->trans, bp);
1409 }
1410 if (i >= 2) {
1411 *action = 0;
Jesper Juhl014c2542006-01-15 02:37:08 +01001412 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 }
1414 xfs_da_buf_done(bp);
1415
1416 /*
1417 * Make altpath point to the block we want to keep (the lower
1418 * numbered block) and path point to the block we want to drop.
1419 */
1420 memcpy(&state->altpath, &state->path, sizeof(state->path));
1421 if (blkno < blk->blkno) {
1422 error = xfs_da_path_shift(state, &state->altpath, forward,
1423 0, &retval);
1424 } else {
1425 error = xfs_da_path_shift(state, &state->path, forward,
1426 0, &retval);
1427 }
1428 if (error)
Jesper Juhl014c2542006-01-15 02:37:08 +01001429 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 if (retval) {
1431 *action = 0;
1432 } else {
1433 *action = 1;
1434 }
Jesper Juhl014c2542006-01-15 02:37:08 +01001435 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436}
1437
1438/*
1439 * Remove a name from the leaf directory structure.
1440 *
1441 * Return 1 if leaf is less than 37% full, 0 if >= 37% full.
1442 * If two leaves are 37% full, when combined they will leave 25% free.
1443 */
1444int
1445xfs_dir_leaf_remove(xfs_trans_t *trans, xfs_dabuf_t *bp, int index)
1446{
1447 xfs_dir_leafblock_t *leaf;
1448 xfs_dir_leaf_hdr_t *hdr;
1449 xfs_dir_leaf_map_t *map;
1450 xfs_dir_leaf_entry_t *entry;
1451 xfs_dir_leaf_name_t *namest;
1452 int before, after, smallest, entsize;
1453 int tablesize, tmp, i;
1454 xfs_mount_t *mp;
1455
1456 leaf = bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +11001457 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 hdr = &leaf->hdr;
1459 mp = trans->t_mountp;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001460 ASSERT(hdr->count && (be16_to_cpu(hdr->count) < (XFS_LBSIZE(mp)/8)));
1461 ASSERT((index >= 0) && (index < be16_to_cpu(hdr->count)));
1462 ASSERT(be16_to_cpu(hdr->firstused) >=
1463 ((be16_to_cpu(hdr->count)*sizeof(*entry))+sizeof(*hdr)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 entry = &leaf->entries[index];
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001465 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= be16_to_cpu(hdr->firstused));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp));
1467
1468 /*
1469 * Scan through free region table:
1470 * check for adjacency of free'd entry with an existing one,
1471 * find smallest free region in case we need to replace it,
1472 * adjust any map that borders the entry table,
1473 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001474 tablesize = be16_to_cpu(hdr->count) * (uint)sizeof(xfs_dir_leaf_entry_t)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 + (uint)sizeof(xfs_dir_leaf_hdr_t);
1476 map = &hdr->freemap[0];
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001477 tmp = be16_to_cpu(map->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 before = after = -1;
1479 smallest = XFS_DIR_LEAF_MAPSIZE - 1;
1480 entsize = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry);
1481 for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) {
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001482 ASSERT(be16_to_cpu(map->base) < XFS_LBSIZE(mp));
1483 ASSERT(be16_to_cpu(map->size) < XFS_LBSIZE(mp));
1484 if (be16_to_cpu(map->base) == tablesize) {
1485 int entry_size = sizeof(xfs_dir_leaf_entry_t);
1486 be16_add(&map->base, -entry_size);
1487 be16_add(&map->size, entry_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 }
1489
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001490 if ((be16_to_cpu(map->base) + be16_to_cpu(map->size)) == INT_GET(entry->nameidx, ARCH_CONVERT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 before = i;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001492 } else if (be16_to_cpu(map->base) == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 after = i;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001494 } else if (be16_to_cpu(map->size) < tmp) {
1495 tmp = be16_to_cpu(map->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 smallest = i;
1497 }
1498 }
1499
1500 /*
1501 * Coalesce adjacent freemap regions,
1502 * or replace the smallest region.
1503 */
1504 if ((before >= 0) || (after >= 0)) {
1505 if ((before >= 0) && (after >= 0)) {
1506 map = &hdr->freemap[before];
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001507 be16_add(&map->size, entsize);
1508 be16_add(&map->size, be16_to_cpu(hdr->freemap[after].size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 hdr->freemap[after].base = 0;
1510 hdr->freemap[after].size = 0;
1511 } else if (before >= 0) {
1512 map = &hdr->freemap[before];
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001513 be16_add(&map->size, entsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 } else {
1515 map = &hdr->freemap[after];
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001516 map->base = entry->nameidx;
1517 be16_add(&map->size, entsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 }
1519 } else {
1520 /*
1521 * Replace smallest region (if it is smaller than free'd entry)
1522 */
1523 map = &hdr->freemap[smallest];
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001524 if (be16_to_cpu(map->size) < entsize) {
1525 map->base = entry->nameidx;
1526 map->size = cpu_to_be16(entsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 }
1528 }
1529
1530 /*
1531 * Did we remove the first entry?
1532 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001533 if (INT_GET(entry->nameidx, ARCH_CONVERT) == be16_to_cpu(hdr->firstused))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 smallest = 1;
1535 else
1536 smallest = 0;
1537
1538 /*
1539 * Compress the remaining entries and zero out the removed stuff.
1540 */
1541 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
1542 memset((char *)namest, 0, entsize);
1543 xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, namest, entsize));
1544
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001545 be16_add(&hdr->namebytes, -(entry->namelen));
1546 tmp = (be16_to_cpu(hdr->count) - index) * (uint)sizeof(xfs_dir_leaf_entry_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 memmove(entry, entry + 1, tmp);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001548 be16_add(&hdr->count, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 xfs_da_log_buf(trans, bp,
1550 XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001551 entry = &leaf->entries[be16_to_cpu(hdr->count)];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 memset((char *)entry, 0, sizeof(xfs_dir_leaf_entry_t));
1553
1554 /*
1555 * If we removed the first entry, re-find the first used byte
1556 * in the name area. Note that if the entry was the "firstused",
1557 * then we don't have a "hole" in our block resulting from
1558 * removing the name.
1559 */
1560 if (smallest) {
1561 tmp = XFS_LBSIZE(mp);
1562 entry = &leaf->entries[0];
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001563 for (i = be16_to_cpu(hdr->count)-1; i >= 0; entry++, i--) {
1564 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >=
1565 be16_to_cpu(hdr->firstused));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp));
1567 if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp)
1568 tmp = INT_GET(entry->nameidx, ARCH_CONVERT);
1569 }
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001570 hdr->firstused = cpu_to_be16(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 if (!hdr->firstused)
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001572 hdr->firstused = cpu_to_be16(tmp - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 } else {
1574 hdr->holes = 1; /* mark as needing compaction */
1575 }
1576
1577 xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
1578
1579 /*
1580 * Check if leaf is less than 50% full, caller may want to
1581 * "join" the leaf with a sibling if so.
1582 */
1583 tmp = (uint)sizeof(xfs_dir_leaf_hdr_t);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001584 tmp += be16_to_cpu(leaf->hdr.count) * (uint)sizeof(xfs_dir_leaf_entry_t);
1585 tmp += be16_to_cpu(leaf->hdr.count) * ((uint)sizeof(xfs_dir_leaf_name_t) - 1);
1586 tmp += be16_to_cpu(leaf->hdr.namebytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 if (tmp < mp->m_dir_magicpct)
Jesper Juhl014c2542006-01-15 02:37:08 +01001588 return 1; /* leaf is < 37% full */
1589 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590}
1591
1592/*
1593 * Move all the directory entries from drop_leaf into save_leaf.
1594 */
1595void
1596xfs_dir_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
1597 xfs_da_state_blk_t *save_blk)
1598{
1599 xfs_dir_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf;
1600 xfs_dir_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr;
1601 xfs_mount_t *mp;
1602 char *tmpbuffer;
1603
1604 /*
1605 * Set up environment.
1606 */
1607 mp = state->mp;
1608 ASSERT(drop_blk->magic == XFS_DIR_LEAF_MAGIC);
1609 ASSERT(save_blk->magic == XFS_DIR_LEAF_MAGIC);
1610 drop_leaf = drop_blk->bp->data;
1611 save_leaf = save_blk->bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +11001612 ASSERT(be16_to_cpu(drop_leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
1613 ASSERT(be16_to_cpu(save_leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 drop_hdr = &drop_leaf->hdr;
1615 save_hdr = &save_leaf->hdr;
1616
1617 /*
1618 * Save last hashval from dying block for later Btree fixup.
1619 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001620 drop_blk->hashval = INT_GET(drop_leaf->entries[be16_to_cpu(drop_leaf->hdr.count)-1].hashval, ARCH_CONVERT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
1622 /*
1623 * Check if we need a temp buffer, or can we do it in place.
1624 * Note that we don't check "leaf" for holes because we will
1625 * always be dropping it, toosmall() decided that for us already.
1626 */
1627 if (save_hdr->holes == 0) {
1628 /*
1629 * dest leaf has no holes, so we add there. May need
1630 * to make some room in the entry array.
1631 */
1632 if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) {
1633 xfs_dir_leaf_moveents(drop_leaf, 0, save_leaf, 0,
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001634 be16_to_cpu(drop_hdr->count), mp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 } else {
1636 xfs_dir_leaf_moveents(drop_leaf, 0,
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001637 save_leaf, be16_to_cpu(save_hdr->count),
1638 be16_to_cpu(drop_hdr->count), mp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 }
1640 } else {
1641 /*
1642 * Destination has holes, so we make a temporary copy
1643 * of the leaf and add them both to that.
1644 */
1645 tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP);
1646 ASSERT(tmpbuffer != NULL);
1647 memset(tmpbuffer, 0, state->blocksize);
1648 tmp_leaf = (xfs_dir_leafblock_t *)tmpbuffer;
1649 tmp_hdr = &tmp_leaf->hdr;
1650 tmp_hdr->info = save_hdr->info; /* struct copy */
1651 tmp_hdr->count = 0;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001652 tmp_hdr->firstused = cpu_to_be16(state->blocksize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 if (!tmp_hdr->firstused)
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001654 tmp_hdr->firstused = cpu_to_be16(state->blocksize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 tmp_hdr->namebytes = 0;
1656 if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) {
1657 xfs_dir_leaf_moveents(drop_leaf, 0, tmp_leaf, 0,
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001658 be16_to_cpu(drop_hdr->count), mp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 xfs_dir_leaf_moveents(save_leaf, 0,
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001660 tmp_leaf, be16_to_cpu(tmp_leaf->hdr.count),
1661 be16_to_cpu(save_hdr->count), mp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 } else {
1663 xfs_dir_leaf_moveents(save_leaf, 0, tmp_leaf, 0,
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001664 be16_to_cpu(save_hdr->count), mp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 xfs_dir_leaf_moveents(drop_leaf, 0,
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001666 tmp_leaf, be16_to_cpu(tmp_leaf->hdr.count),
1667 be16_to_cpu(drop_hdr->count), mp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 }
1669 memcpy(save_leaf, tmp_leaf, state->blocksize);
1670 kmem_free(tmpbuffer, state->blocksize);
1671 }
1672
1673 xfs_da_log_buf(state->args->trans, save_blk->bp, 0,
1674 state->blocksize - 1);
1675
1676 /*
1677 * Copy out last hashval in each block for B-tree code.
1678 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001679 save_blk->hashval = INT_GET(save_leaf->entries[be16_to_cpu(save_leaf->hdr.count)-1 ].hashval, ARCH_CONVERT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680}
1681
1682/*========================================================================
1683 * Routines used for finding things in the Btree.
1684 *========================================================================*/
1685
1686/*
1687 * Look up a name in a leaf directory structure.
1688 * This is the internal routine, it uses the caller's buffer.
1689 *
1690 * Note that duplicate keys are allowed, but only check within the
1691 * current leaf node. The Btree code must check in adjacent leaf nodes.
1692 *
1693 * Return in *index the index into the entry[] array of either the found
1694 * entry, or where the entry should have been (insert before that entry).
1695 *
1696 * Don't change the args->inumber unless we find the filename.
1697 */
1698int
1699xfs_dir_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args, int *index)
1700{
1701 xfs_dir_leafblock_t *leaf;
1702 xfs_dir_leaf_entry_t *entry;
1703 xfs_dir_leaf_name_t *namest;
1704 int probe, span;
1705 xfs_dahash_t hashval;
1706
1707 leaf = bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +11001708 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001709 ASSERT(be16_to_cpu(leaf->hdr.count) < (XFS_LBSIZE(args->dp->i_mount)/8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
1711 /*
1712 * Binary search. (note: small blocks will skip this loop)
1713 */
1714 hashval = args->hashval;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001715 probe = span = be16_to_cpu(leaf->hdr.count) / 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 for (entry = &leaf->entries[probe]; span > 4;
1717 entry = &leaf->entries[probe]) {
1718 span /= 2;
1719 if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)
1720 probe += span;
1721 else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval)
1722 probe -= span;
1723 else
1724 break;
1725 }
1726 ASSERT((probe >= 0) && \
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001727 ((!leaf->hdr.count) || (probe < be16_to_cpu(leaf->hdr.count))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) == hashval));
1729
1730 /*
1731 * Since we may have duplicate hashval's, find the first matching
1732 * hashval in the leaf.
1733 */
1734 while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) >= hashval)) {
1735 entry--;
1736 probe--;
1737 }
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001738 while ((probe < be16_to_cpu(leaf->hdr.count)) && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 entry++;
1740 probe++;
1741 }
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001742 if ((probe == be16_to_cpu(leaf->hdr.count)) || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 *index = probe;
1744 ASSERT(args->oknoent);
Jesper Juhl014c2542006-01-15 02:37:08 +01001745 return XFS_ERROR(ENOENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 }
1747
1748 /*
1749 * Duplicate keys may be present, so search all of them for a match.
1750 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001751 while ((probe < be16_to_cpu(leaf->hdr.count)) && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
1753 if (entry->namelen == args->namelen &&
1754 namest->name[0] == args->name[0] &&
1755 memcmp(args->name, namest->name, args->namelen) == 0) {
1756 XFS_DIR_SF_GET_DIRINO(&namest->inumber, &args->inumber);
1757 *index = probe;
Jesper Juhl014c2542006-01-15 02:37:08 +01001758 return XFS_ERROR(EEXIST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 }
1760 entry++;
1761 probe++;
1762 }
1763 *index = probe;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001764 ASSERT(probe == be16_to_cpu(leaf->hdr.count) || args->oknoent);
Jesper Juhl014c2542006-01-15 02:37:08 +01001765 return XFS_ERROR(ENOENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766}
1767
1768/*========================================================================
1769 * Utility routines.
1770 *========================================================================*/
1771
1772/*
1773 * Move the indicated entries from one leaf to another.
1774 * NOTE: this routine modifies both source and destination leaves.
1775 */
1776/* ARGSUSED */
1777STATIC void
1778xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s,
1779 xfs_dir_leafblock_t *leaf_d, int start_d,
1780 int count, xfs_mount_t *mp)
1781{
1782 xfs_dir_leaf_hdr_t *hdr_s, *hdr_d;
1783 xfs_dir_leaf_entry_t *entry_s, *entry_d;
1784 int tmp, i;
1785
1786 /*
1787 * Check for nothing to do.
1788 */
1789 if (count == 0)
1790 return;
1791
1792 /*
1793 * Set up environment.
1794 */
Nathan Scott89da0542006-03-17 17:28:40 +11001795 ASSERT(be16_to_cpu(leaf_s->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
1796 ASSERT(be16_to_cpu(leaf_d->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 hdr_s = &leaf_s->hdr;
1798 hdr_d = &leaf_d->hdr;
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001799 ASSERT(hdr_s->count && (be16_to_cpu(hdr_s->count) < (XFS_LBSIZE(mp)/8)));
1800 ASSERT(be16_to_cpu(hdr_s->firstused) >=
1801 ((be16_to_cpu(hdr_s->count)*sizeof(*entry_s))+sizeof(*hdr_s)));
1802 ASSERT(be16_to_cpu(hdr_d->count) < (XFS_LBSIZE(mp)/8));
1803 ASSERT(be16_to_cpu(hdr_d->firstused) >=
1804 ((be16_to_cpu(hdr_d->count)*sizeof(*entry_d))+sizeof(*hdr_d)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001806 ASSERT(start_s < be16_to_cpu(hdr_s->count));
1807 ASSERT(start_d <= be16_to_cpu(hdr_d->count));
1808 ASSERT(count <= be16_to_cpu(hdr_s->count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809
1810 /*
1811 * Move the entries in the destination leaf up to make a hole?
1812 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001813 if (start_d < be16_to_cpu(hdr_d->count)) {
1814 tmp = be16_to_cpu(hdr_d->count) - start_d;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
1816 entry_s = &leaf_d->entries[start_d];
1817 entry_d = &leaf_d->entries[start_d + count];
1818 memcpy(entry_d, entry_s, tmp);
1819 }
1820
1821 /*
1822 * Copy all entry's in the same (sorted) order,
1823 * but allocate filenames packed and in sequence.
1824 */
1825 entry_s = &leaf_s->entries[start_s];
1826 entry_d = &leaf_d->entries[start_d];
1827 for (i = 0; i < count; entry_s++, entry_d++, i++) {
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001828 ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) >=
1829 be16_to_cpu(hdr_s->firstused));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 tmp = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry_s);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001831 be16_add(&hdr_d->firstused, -(tmp));
1832 entry_d->hashval = entry_s->hashval;
1833 entry_d->nameidx = hdr_d->firstused;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 entry_d->namelen = entry_s->namelen;
1835 ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
1836 memcpy(XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)),
1837 XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), tmp);
1838 ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
1839 memset((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)),
1840 0, tmp);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001841 be16_add(&hdr_s->namebytes, -(entry_d->namelen));
1842 be16_add(&hdr_d->namebytes, entry_d->namelen);
1843 be16_add(&hdr_s->count, -1);
1844 be16_add(&hdr_d->count, +1);
1845 tmp = be16_to_cpu(hdr_d->count) * (uint)sizeof(xfs_dir_leaf_entry_t)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 + (uint)sizeof(xfs_dir_leaf_hdr_t);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001847 ASSERT(be16_to_cpu(hdr_d->firstused) >= tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
1849 }
1850
1851 /*
1852 * Zero out the entries we just copied.
1853 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001854 if (start_s == be16_to_cpu(hdr_s->count)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
1856 entry_s = &leaf_s->entries[start_s];
1857 ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
1858 memset((char *)entry_s, 0, tmp);
1859 } else {
1860 /*
1861 * Move the remaining entries down to fill the hole,
1862 * then zero the entries at the top.
1863 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001864 tmp = be16_to_cpu(hdr_s->count) - count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
1866 entry_s = &leaf_s->entries[start_s + count];
1867 entry_d = &leaf_s->entries[start_s];
1868 memcpy(entry_d, entry_s, tmp);
1869
1870 tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001871 entry_s = &leaf_s->entries[be16_to_cpu(hdr_s->count)];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
1873 memset((char *)entry_s, 0, tmp);
1874 }
1875
1876 /*
1877 * Fill in the freemap information
1878 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001879 hdr_d->freemap[0].base = cpu_to_be16(sizeof(xfs_dir_leaf_hdr_t) +
1880 be16_to_cpu(hdr_d->count) * sizeof(xfs_dir_leaf_entry_t));
1881 hdr_d->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr_d->firstused) -
1882 be16_to_cpu(hdr_d->freemap[0].base));
1883 hdr_d->freemap[1].base = 0;
1884 hdr_d->freemap[1].size = 0;
1885 hdr_d->freemap[2].base = 0;
1886 hdr_d->freemap[2].size = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 hdr_s->holes = 1; /* leaf may not be compact */
1888}
1889
1890/*
1891 * Compare two leaf blocks "order".
1892 */
1893int
1894xfs_dir_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp)
1895{
1896 xfs_dir_leafblock_t *leaf1, *leaf2;
1897
1898 leaf1 = leaf1_bp->data;
1899 leaf2 = leaf2_bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +11001900 ASSERT((be16_to_cpu(leaf1->hdr.info.magic) == XFS_DIR_LEAF_MAGIC) &&
1901 (be16_to_cpu(leaf2->hdr.info.magic) == XFS_DIR_LEAF_MAGIC));
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001902 if (leaf1->hdr.count && leaf2->hdr.count &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 ((INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) <
1904 INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) ||
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001905 (INT_GET(leaf2->entries[be16_to_cpu(leaf2->hdr.count)-1].hashval, ARCH_CONVERT) <
1906 INT_GET(leaf1->entries[be16_to_cpu(leaf1->hdr.count)-1].hashval, ARCH_CONVERT)))) {
Jesper Juhl014c2542006-01-15 02:37:08 +01001907 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 }
Jesper Juhl014c2542006-01-15 02:37:08 +01001909 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910}
1911
1912/*
1913 * Pick up the last hashvalue from a leaf block.
1914 */
1915xfs_dahash_t
1916xfs_dir_leaf_lasthash(xfs_dabuf_t *bp, int *count)
1917{
1918 xfs_dir_leafblock_t *leaf;
1919
1920 leaf = bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +11001921 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (count)
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001923 *count = be16_to_cpu(leaf->hdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 if (!leaf->hdr.count)
1925 return(0);
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001926 return(INT_GET(leaf->entries[be16_to_cpu(leaf->hdr.count)-1].hashval, ARCH_CONVERT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927}
1928
1929/*
1930 * Copy out directory entries for getdents(), for leaf directories.
1931 */
1932int
1933xfs_dir_leaf_getdents_int(
1934 xfs_dabuf_t *bp,
1935 xfs_inode_t *dp,
1936 xfs_dablk_t bno,
1937 uio_t *uio,
1938 int *eobp,
1939 xfs_dirent_t *dbp,
1940 xfs_dir_put_t put,
1941 xfs_daddr_t nextda)
1942{
1943 xfs_dir_leafblock_t *leaf;
1944 xfs_dir_leaf_entry_t *entry;
1945 xfs_dir_leaf_name_t *namest;
1946 int entno, want_entno, i, nextentno;
1947 xfs_mount_t *mp;
1948 xfs_dahash_t cookhash;
1949 xfs_dahash_t nexthash = 0;
1950#if (BITS_PER_LONG == 32)
1951 xfs_dahash_t lasthash = XFS_DA_MAXHASH;
1952#endif
1953 xfs_dir_put_args_t p;
1954
1955 mp = dp->i_mount;
1956 leaf = bp->data;
Nathan Scott89da0542006-03-17 17:28:40 +11001957 if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 *eobp = 1;
Jesper Juhl014c2542006-01-15 02:37:08 +01001959 return XFS_ERROR(ENOENT); /* XXX wrong code */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 }
1961
1962 want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset);
1963
1964 cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset);
1965
1966 xfs_dir_trace_g_dul("leaf: start", dp, uio, leaf);
1967
1968 /*
1969 * Re-find our place.
1970 */
1971 for (i = entno = 0, entry = &leaf->entries[0];
Christoph Hellwig8034fff2006-06-09 14:50:24 +10001972 i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
1974 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
1975 INT_GET(entry->nameidx, ARCH_CONVERT));
1976
1977 if (unlikely(
1978 ((char *)namest < (char *)leaf) ||
1979 ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)))) {
1980 XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(1)",
1981 XFS_ERRLEVEL_LOW, mp, leaf);
1982 xfs_dir_trace_g_du("leaf: corrupted", dp, uio);
1983 return XFS_ERROR(EFSCORRUPTED);
1984 }
1985 if (INT_GET(entry->hashval, ARCH_CONVERT) >= cookhash) {
1986 if ( entno < want_entno
1987 && INT_GET(entry->hashval, ARCH_CONVERT)
1988 == cookhash) {
1989 /*
1990 * Trying to get to a particular offset in a
1991 * run of equal-hashval entries.
1992 */
1993 entno++;
1994 } else if ( want_entno > 0
1995 && entno == want_entno
1996 && INT_GET(entry->hashval, ARCH_CONVERT)
1997 == cookhash) {
1998 break;
1999 } else {
2000 entno = 0;
2001 break;
2002 }
2003 }
2004 }
2005
Christoph Hellwig8034fff2006-06-09 14:50:24 +10002006 if (i == be16_to_cpu(leaf->hdr.count)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 xfs_dir_trace_g_du("leaf: hash not found", dp, uio);
Nathan Scott89da0542006-03-17 17:28:40 +11002008 if (!leaf->hdr.info.forw)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 uio->uio_offset =
2010 XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH);
2011 /*
2012 * Don't set uio_offset if there's another block:
2013 * the node code will be setting uio_offset anyway.
2014 */
2015 *eobp = 0;
Jesper Juhl014c2542006-01-15 02:37:08 +01002016 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 }
2018 xfs_dir_trace_g_due("leaf: hash found", dp, uio, entry);
2019
2020 p.dbp = dbp;
2021 p.put = put;
2022 p.uio = uio;
2023
2024 /*
2025 * We're synchronized, start copying entries out to the user.
2026 */
Christoph Hellwig8034fff2006-06-09 14:50:24 +10002027 for (; entno >= 0 && i < be16_to_cpu(leaf->hdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 entry++, i++, (entno = nextentno)) {
2029 int lastresid=0, retval;
2030 xfs_dircook_t lastoffset;
2031 xfs_dahash_t thishash;
2032
2033 /*
2034 * Check for a damaged directory leaf block and pick up
2035 * the inode number from this entry.
2036 */
2037 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
2038 INT_GET(entry->nameidx, ARCH_CONVERT));
2039
2040 if (unlikely(
2041 ((char *)namest < (char *)leaf) ||
2042 ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)))) {
2043 XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(2)",
2044 XFS_ERRLEVEL_LOW, mp, leaf);
2045 xfs_dir_trace_g_du("leaf: corrupted", dp, uio);
2046 return XFS_ERROR(EFSCORRUPTED);
2047 }
2048
2049 xfs_dir_trace_g_duc("leaf: middle cookie ",
2050 dp, uio, p.cook.o);
2051
Christoph Hellwig8034fff2006-06-09 14:50:24 +10002052 if (i < (be16_to_cpu(leaf->hdr.count) - 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 nexthash = INT_GET(entry[1].hashval, ARCH_CONVERT);
2054
2055 if (nexthash == INT_GET(entry->hashval, ARCH_CONVERT))
2056 nextentno = entno + 1;
2057 else
2058 nextentno = 0;
2059 XFS_PUT_COOKIE(p.cook, mp, bno, nextentno, nexthash);
2060 xfs_dir_trace_g_duc("leaf: middle cookie ",
2061 dp, uio, p.cook.o);
2062
Nathan Scott89da0542006-03-17 17:28:40 +11002063 } else if ((thishash = be32_to_cpu(leaf->hdr.info.forw))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 xfs_dabuf_t *bp2;
2065 xfs_dir_leafblock_t *leaf2;
2066
2067 ASSERT(nextda != -1);
2068
2069 retval = xfs_da_read_buf(dp->i_transp, dp, thishash,
2070 nextda, &bp2, XFS_DATA_FORK);
2071 if (retval)
Jesper Juhl014c2542006-01-15 02:37:08 +01002072 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
2074 ASSERT(bp2 != NULL);
2075
2076 leaf2 = bp2->data;
2077
2078 if (unlikely(
Nathan Scott89da0542006-03-17 17:28:40 +11002079 (be16_to_cpu(leaf2->hdr.info.magic)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 != XFS_DIR_LEAF_MAGIC)
Nathan Scott89da0542006-03-17 17:28:40 +11002081 || (be32_to_cpu(leaf2->hdr.info.back)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 != bno))) { /* GROT */
2083 XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(3)",
2084 XFS_ERRLEVEL_LOW, mp,
2085 leaf2);
2086 xfs_da_brelse(dp->i_transp, bp2);
2087
Jesper Juhl014c2542006-01-15 02:37:08 +01002088 return XFS_ERROR(EFSCORRUPTED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 }
2090
2091 nexthash = INT_GET(leaf2->entries[0].hashval,
2092 ARCH_CONVERT);
2093 nextentno = -1;
2094 XFS_PUT_COOKIE(p.cook, mp, thishash, 0, nexthash);
2095 xfs_da_brelse(dp->i_transp, bp2);
2096 xfs_dir_trace_g_duc("leaf: next blk cookie",
2097 dp, uio, p.cook.o);
2098 } else {
2099 nextentno = -1;
2100 XFS_PUT_COOKIE(p.cook, mp, 0, 0, XFS_DA_MAXHASH);
2101 }
2102
2103 /*
2104 * Save off the cookie so we can fall back should the
2105 * 'put' into the outgoing buffer fails. To handle a run
2106 * of equal-hashvals, the off_t structure on 64bit
2107 * builds has entno built into the cookie to ID the
2108 * entry. On 32bit builds, we only have space for the
2109 * hashval so we can't ID specific entries within a group
2110 * of same hashval entries. For this, lastoffset is set
2111 * to the first in the run of equal hashvals so we don't
2112 * include any entries unless we can include all entries
2113 * that share the same hashval. Hopefully the buffer
2114 * provided is big enough to handle it (see pv763517).
2115 */
2116#if (BITS_PER_LONG == 32)
2117 if ((thishash = INT_GET(entry->hashval, ARCH_CONVERT))
2118 != lasthash) {
2119 XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash);
2120 lastresid = uio->uio_resid;
2121 lasthash = thishash;
2122 } else {
2123 xfs_dir_trace_g_duc("leaf: DUP COOKIES, skipped",
2124 dp, uio, p.cook.o);
2125 }
2126#else
2127 thishash = INT_GET(entry->hashval, ARCH_CONVERT);
2128 XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash);
2129 lastresid = uio->uio_resid;
2130#endif /* BITS_PER_LONG == 32 */
2131
2132 /*
2133 * Put the current entry into the outgoing buffer. If we fail
2134 * then restore the UIO to the first entry in the current
2135 * run of equal-hashval entries (probably one 1 entry long).
2136 */
2137 p.ino = XFS_GET_DIR_INO8(namest->inumber);
2138#if XFS_BIG_INUMS
2139 p.ino += mp->m_inoadd;
2140#endif
2141 p.name = (char *)namest->name;
2142 p.namelen = entry->namelen;
2143
2144 retval = p.put(&p);
2145
2146 if (!p.done) {
2147 uio->uio_offset = lastoffset.o;
2148 uio->uio_resid = lastresid;
2149
2150 *eobp = 1;
2151
2152 xfs_dir_trace_g_du("leaf: E-O-B", dp, uio);
2153
Jesper Juhl014c2542006-01-15 02:37:08 +01002154 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 }
2156 }
2157
2158 uio->uio_offset = p.cook.o;
2159
2160 *eobp = 0;
2161
2162 xfs_dir_trace_g_du("leaf: E-O-F", dp, uio);
2163
Jesper Juhl014c2542006-01-15 02:37:08 +01002164 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165}
2166
2167/*
2168 * Format a dirent64 structure and copy it out the the user's buffer.
2169 */
2170int
2171xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa)
2172{
2173 iovec_t *iovp;
2174 int reclen, namelen;
2175 xfs_dirent_t *idbp;
2176 uio_t *uio;
2177
2178 namelen = pa->namelen;
2179 reclen = DIRENTSIZE(namelen);
2180 uio = pa->uio;
2181 if (reclen > uio->uio_resid) {
2182 pa->done = 0;
2183 return 0;
2184 }
2185 iovp = uio->uio_iov;
2186 idbp = (xfs_dirent_t *)iovp->iov_base;
2187 iovp->iov_base = (char *)idbp + reclen;
2188 iovp->iov_len -= reclen;
2189 uio->uio_resid -= reclen;
2190 idbp->d_reclen = reclen;
2191 idbp->d_ino = pa->ino;
2192 idbp->d_off = pa->cook.o;
2193 idbp->d_name[namelen] = '\0';
2194 pa->done = 1;
2195 memcpy(idbp->d_name, pa->name, namelen);
2196 return 0;
2197}
2198
2199/*
2200 * Format a dirent64 structure and copy it out the the user's buffer.
2201 */
2202int
2203xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa)
2204{
2205 int retval, reclen, namelen;
2206 xfs_dirent_t *idbp;
2207 uio_t *uio;
2208
2209 namelen = pa->namelen;
2210 reclen = DIRENTSIZE(namelen);
2211 uio = pa->uio;
2212 if (reclen > uio->uio_resid) {
2213 pa->done = 0;
2214 return 0;
2215 }
2216 idbp = pa->dbp;
2217 idbp->d_reclen = reclen;
2218 idbp->d_ino = pa->ino;
2219 idbp->d_off = pa->cook.o;
2220 idbp->d_name[namelen] = '\0';
2221 memcpy(idbp->d_name, pa->name, namelen);
2222 retval = uio_read((caddr_t)idbp, reclen, uio);
2223 pa->done = (retval == 0);
2224 return retval;
2225}