]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxfs/xfs_dir2.c
xfs: create structure verifier function for shortform xattrs
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_dir2.c
1 /*
2 * Copyright (c) 2000-2001,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 "libxfs_priv.h"
19 #include "xfs_fs.h"
20 #include "xfs_format.h"
21 #include "xfs_log_format.h"
22 #include "xfs_trans_resv.h"
23 #include "xfs_mount.h"
24 #include "xfs_defer.h"
25 #include "xfs_da_format.h"
26 #include "xfs_da_btree.h"
27 #include "xfs_inode.h"
28 #include "xfs_trans.h"
29 #include "xfs_bmap.h"
30 #include "xfs_dir2.h"
31 #include "xfs_dir2_priv.h"
32 #include "xfs_ialloc.h"
33 #include "xfs_errortag.h"
34 #include "xfs_trace.h"
35
36 struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
37
38 /*
39 * Convert inode mode to directory entry filetype
40 */
41 unsigned char
42 xfs_mode_to_ftype(
43 int mode)
44 {
45 switch (mode & S_IFMT) {
46 case S_IFREG:
47 return XFS_DIR3_FT_REG_FILE;
48 case S_IFDIR:
49 return XFS_DIR3_FT_DIR;
50 case S_IFCHR:
51 return XFS_DIR3_FT_CHRDEV;
52 case S_IFBLK:
53 return XFS_DIR3_FT_BLKDEV;
54 case S_IFIFO:
55 return XFS_DIR3_FT_FIFO;
56 case S_IFSOCK:
57 return XFS_DIR3_FT_SOCK;
58 case S_IFLNK:
59 return XFS_DIR3_FT_SYMLINK;
60 default:
61 return XFS_DIR3_FT_UNKNOWN;
62 }
63 }
64
65 /*
66 * ASCII case-insensitive (ie. A-Z) support for directories that was
67 * used in IRIX.
68 */
69 STATIC xfs_dahash_t
70 xfs_ascii_ci_hashname(
71 struct xfs_name *name)
72 {
73 xfs_dahash_t hash;
74 int i;
75
76 for (i = 0, hash = 0; i < name->len; i++)
77 hash = tolower(name->name[i]) ^ rol32(hash, 7);
78
79 return hash;
80 }
81
82 STATIC enum xfs_dacmp
83 xfs_ascii_ci_compname(
84 struct xfs_da_args *args,
85 const unsigned char *name,
86 int len)
87 {
88 enum xfs_dacmp result;
89 int i;
90
91 if (args->namelen != len)
92 return XFS_CMP_DIFFERENT;
93
94 result = XFS_CMP_EXACT;
95 for (i = 0; i < len; i++) {
96 if (args->name[i] == name[i])
97 continue;
98 if (tolower(args->name[i]) != tolower(name[i]))
99 return XFS_CMP_DIFFERENT;
100 result = XFS_CMP_CASE;
101 }
102
103 return result;
104 }
105
106 static const struct xfs_nameops xfs_ascii_ci_nameops = {
107 .hashname = xfs_ascii_ci_hashname,
108 .compname = xfs_ascii_ci_compname,
109 };
110
111 int
112 xfs_da_mount(
113 struct xfs_mount *mp)
114 {
115 struct xfs_da_geometry *dageo;
116 int nodehdr_size;
117
118
119 ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
120 ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
121 XFS_MAX_BLOCKSIZE);
122
123 mp->m_dir_inode_ops = xfs_dir_get_ops(mp, NULL);
124 mp->m_nondir_inode_ops = xfs_nondir_get_ops(mp, NULL);
125
126 nodehdr_size = mp->m_dir_inode_ops->node_hdr_size;
127 mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
128 KM_SLEEP | KM_MAYFAIL);
129 mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
130 KM_SLEEP | KM_MAYFAIL);
131 if (!mp->m_dir_geo || !mp->m_attr_geo) {
132 kmem_free(mp->m_dir_geo);
133 kmem_free(mp->m_attr_geo);
134 return -ENOMEM;
135 }
136
137 /* set up directory geometry */
138 dageo = mp->m_dir_geo;
139 dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog;
140 dageo->fsblog = mp->m_sb.sb_blocklog;
141 dageo->blksize = 1 << dageo->blklog;
142 dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
143
144 /*
145 * Now we've set up the block conversion variables, we can calculate the
146 * segment block constants using the geometry structure.
147 */
148 dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);
149 dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);
150 dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
151 dageo->node_ents = (dageo->blksize - nodehdr_size) /
152 (uint)sizeof(xfs_da_node_entry_t);
153 dageo->magicpct = (dageo->blksize * 37) / 100;
154
155 /* set up attribute geometry - single fsb only */
156 dageo = mp->m_attr_geo;
157 dageo->blklog = mp->m_sb.sb_blocklog;
158 dageo->fsblog = mp->m_sb.sb_blocklog;
159 dageo->blksize = 1 << dageo->blklog;
160 dageo->fsbcount = 1;
161 dageo->node_ents = (dageo->blksize - nodehdr_size) /
162 (uint)sizeof(xfs_da_node_entry_t);
163 dageo->magicpct = (dageo->blksize * 37) / 100;
164
165 if (xfs_sb_version_hasasciici(&mp->m_sb))
166 mp->m_dirnameops = &xfs_ascii_ci_nameops;
167 else
168 mp->m_dirnameops = &xfs_default_nameops;
169
170 return 0;
171 }
172
173 void
174 xfs_da_unmount(
175 struct xfs_mount *mp)
176 {
177 kmem_free(mp->m_dir_geo);
178 kmem_free(mp->m_attr_geo);
179 }
180
181 /*
182 * Return 1 if directory contains only "." and "..".
183 */
184 int
185 xfs_dir_isempty(
186 xfs_inode_t *dp)
187 {
188 xfs_dir2_sf_hdr_t *sfp;
189
190 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
191 if (dp->i_d.di_size == 0) /* might happen during shutdown. */
192 return 1;
193 if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
194 return 0;
195 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
196 return !sfp->count;
197 }
198
199 /*
200 * Validate a given inode number.
201 */
202 int
203 xfs_dir_ino_validate(
204 xfs_mount_t *mp,
205 xfs_ino_t ino)
206 {
207 bool ino_ok = xfs_verify_dir_ino(mp, ino);
208
209 if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) {
210 xfs_warn(mp, "Invalid inode number 0x%Lx",
211 (unsigned long long) ino);
212 XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
213 return -EFSCORRUPTED;
214 }
215 return 0;
216 }
217
218 /*
219 * Initialize a directory with its "." and ".." entries.
220 */
221 int
222 xfs_dir_init(
223 xfs_trans_t *tp,
224 xfs_inode_t *dp,
225 xfs_inode_t *pdp)
226 {
227 struct xfs_da_args *args;
228 int error;
229
230 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
231 error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino);
232 if (error)
233 return error;
234
235 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
236 if (!args)
237 return -ENOMEM;
238
239 args->geo = dp->i_mount->m_dir_geo;
240 args->dp = dp;
241 args->trans = tp;
242 error = xfs_dir2_sf_create(args, pdp->i_ino);
243 kmem_free(args);
244 return error;
245 }
246
247 /*
248 * Enter a name in a directory, or check for available space.
249 * If inum is 0, only the available space test is performed.
250 */
251 int
252 xfs_dir_createname(
253 xfs_trans_t *tp,
254 xfs_inode_t *dp,
255 struct xfs_name *name,
256 xfs_ino_t inum, /* new entry inode number */
257 xfs_fsblock_t *first, /* bmap's firstblock */
258 struct xfs_defer_ops *dfops, /* bmap's freeblock list */
259 xfs_extlen_t total) /* bmap's total block count */
260 {
261 struct xfs_da_args *args;
262 int rval;
263 int v; /* type-checking value */
264
265 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
266 if (inum) {
267 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
268 if (rval)
269 return rval;
270 XFS_STATS_INC(dp->i_mount, xs_dir_create);
271 }
272
273 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
274 if (!args)
275 return -ENOMEM;
276
277 args->geo = dp->i_mount->m_dir_geo;
278 args->name = name->name;
279 args->namelen = name->len;
280 args->filetype = name->type;
281 args->hashval = dp->i_mount->m_dirnameops->hashname(name);
282 args->inumber = inum;
283 args->dp = dp;
284 args->firstblock = first;
285 args->dfops = dfops;
286 args->total = total;
287 args->whichfork = XFS_DATA_FORK;
288 args->trans = tp;
289 args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
290 if (!inum)
291 args->op_flags |= XFS_DA_OP_JUSTCHECK;
292
293 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
294 rval = xfs_dir2_sf_addname(args);
295 goto out_free;
296 }
297
298 rval = xfs_dir2_isblock(args, &v);
299 if (rval)
300 goto out_free;
301 if (v) {
302 rval = xfs_dir2_block_addname(args);
303 goto out_free;
304 }
305
306 rval = xfs_dir2_isleaf(args, &v);
307 if (rval)
308 goto out_free;
309 if (v)
310 rval = xfs_dir2_leaf_addname(args);
311 else
312 rval = xfs_dir2_node_addname(args);
313
314 out_free:
315 kmem_free(args);
316 return rval;
317 }
318
319 /*
320 * If doing a CI lookup and case-insensitive match, dup actual name into
321 * args.value. Return EEXIST for success (ie. name found) or an error.
322 */
323 int
324 xfs_dir_cilookup_result(
325 struct xfs_da_args *args,
326 const unsigned char *name,
327 int len)
328 {
329 if (args->cmpresult == XFS_CMP_DIFFERENT)
330 return -ENOENT;
331 if (args->cmpresult != XFS_CMP_CASE ||
332 !(args->op_flags & XFS_DA_OP_CILOOKUP))
333 return -EEXIST;
334
335 args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);
336 if (!args->value)
337 return -ENOMEM;
338
339 memcpy(args->value, name, len);
340 args->valuelen = len;
341 return -EEXIST;
342 }
343
344 /*
345 * Lookup a name in a directory, give back the inode number.
346 * If ci_name is not NULL, returns the actual name in ci_name if it differs
347 * to name, or ci_name->name is set to NULL for an exact match.
348 */
349
350 int
351 xfs_dir_lookup(
352 xfs_trans_t *tp,
353 xfs_inode_t *dp,
354 struct xfs_name *name,
355 xfs_ino_t *inum, /* out: inode number */
356 struct xfs_name *ci_name) /* out: actual name if CI match */
357 {
358 struct xfs_da_args *args;
359 int rval;
360 int v; /* type-checking value */
361 int lock_mode;
362
363 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
364 XFS_STATS_INC(dp->i_mount, xs_dir_lookup);
365
366 /*
367 * We need to use KM_NOFS here so that lockdep will not throw false
368 * positive deadlock warnings on a non-transactional lookup path. It is
369 * safe to recurse into inode recalim in that case, but lockdep can't
370 * easily be taught about it. Hence KM_NOFS avoids having to add more
371 * lockdep Doing this avoids having to add a bunch of lockdep class
372 * annotations into the reclaim path for the ilock.
373 */
374 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
375 args->geo = dp->i_mount->m_dir_geo;
376 args->name = name->name;
377 args->namelen = name->len;
378 args->filetype = name->type;
379 args->hashval = dp->i_mount->m_dirnameops->hashname(name);
380 args->dp = dp;
381 args->whichfork = XFS_DATA_FORK;
382 args->trans = tp;
383 args->op_flags = XFS_DA_OP_OKNOENT;
384 if (ci_name)
385 args->op_flags |= XFS_DA_OP_CILOOKUP;
386
387 lock_mode = xfs_ilock_data_map_shared(dp);
388 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
389 rval = xfs_dir2_sf_lookup(args);
390 goto out_check_rval;
391 }
392
393 rval = xfs_dir2_isblock(args, &v);
394 if (rval)
395 goto out_free;
396 if (v) {
397 rval = xfs_dir2_block_lookup(args);
398 goto out_check_rval;
399 }
400
401 rval = xfs_dir2_isleaf(args, &v);
402 if (rval)
403 goto out_free;
404 if (v)
405 rval = xfs_dir2_leaf_lookup(args);
406 else
407 rval = xfs_dir2_node_lookup(args);
408
409 out_check_rval:
410 if (rval == -EEXIST)
411 rval = 0;
412 if (!rval) {
413 *inum = args->inumber;
414 if (ci_name) {
415 ci_name->name = args->value;
416 ci_name->len = args->valuelen;
417 }
418 }
419 out_free:
420 xfs_iunlock(dp, lock_mode);
421 kmem_free(args);
422 return rval;
423 }
424
425 /*
426 * Remove an entry from a directory.
427 */
428 int
429 xfs_dir_removename(
430 xfs_trans_t *tp,
431 xfs_inode_t *dp,
432 struct xfs_name *name,
433 xfs_ino_t ino,
434 xfs_fsblock_t *first, /* bmap's firstblock */
435 struct xfs_defer_ops *dfops, /* bmap's freeblock list */
436 xfs_extlen_t total) /* bmap's total block count */
437 {
438 struct xfs_da_args *args;
439 int rval;
440 int v; /* type-checking value */
441
442 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
443 XFS_STATS_INC(dp->i_mount, xs_dir_remove);
444
445 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
446 if (!args)
447 return -ENOMEM;
448
449 args->geo = dp->i_mount->m_dir_geo;
450 args->name = name->name;
451 args->namelen = name->len;
452 args->filetype = name->type;
453 args->hashval = dp->i_mount->m_dirnameops->hashname(name);
454 args->inumber = ino;
455 args->dp = dp;
456 args->firstblock = first;
457 args->dfops = dfops;
458 args->total = total;
459 args->whichfork = XFS_DATA_FORK;
460 args->trans = tp;
461
462 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
463 rval = xfs_dir2_sf_removename(args);
464 goto out_free;
465 }
466
467 rval = xfs_dir2_isblock(args, &v);
468 if (rval)
469 goto out_free;
470 if (v) {
471 rval = xfs_dir2_block_removename(args);
472 goto out_free;
473 }
474
475 rval = xfs_dir2_isleaf(args, &v);
476 if (rval)
477 goto out_free;
478 if (v)
479 rval = xfs_dir2_leaf_removename(args);
480 else
481 rval = xfs_dir2_node_removename(args);
482 out_free:
483 kmem_free(args);
484 return rval;
485 }
486
487 /*
488 * Replace the inode number of a directory entry.
489 */
490 int
491 xfs_dir_replace(
492 xfs_trans_t *tp,
493 xfs_inode_t *dp,
494 struct xfs_name *name, /* name of entry to replace */
495 xfs_ino_t inum, /* new inode number */
496 xfs_fsblock_t *first, /* bmap's firstblock */
497 struct xfs_defer_ops *dfops, /* bmap's freeblock list */
498 xfs_extlen_t total) /* bmap's total block count */
499 {
500 struct xfs_da_args *args;
501 int rval;
502 int v; /* type-checking value */
503
504 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
505
506 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
507 if (rval)
508 return rval;
509
510 args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
511 if (!args)
512 return -ENOMEM;
513
514 args->geo = dp->i_mount->m_dir_geo;
515 args->name = name->name;
516 args->namelen = name->len;
517 args->filetype = name->type;
518 args->hashval = dp->i_mount->m_dirnameops->hashname(name);
519 args->inumber = inum;
520 args->dp = dp;
521 args->firstblock = first;
522 args->dfops = dfops;
523 args->total = total;
524 args->whichfork = XFS_DATA_FORK;
525 args->trans = tp;
526
527 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
528 rval = xfs_dir2_sf_replace(args);
529 goto out_free;
530 }
531
532 rval = xfs_dir2_isblock(args, &v);
533 if (rval)
534 goto out_free;
535 if (v) {
536 rval = xfs_dir2_block_replace(args);
537 goto out_free;
538 }
539
540 rval = xfs_dir2_isleaf(args, &v);
541 if (rval)
542 goto out_free;
543 if (v)
544 rval = xfs_dir2_leaf_replace(args);
545 else
546 rval = xfs_dir2_node_replace(args);
547 out_free:
548 kmem_free(args);
549 return rval;
550 }
551
552 /*
553 * See if this entry can be added to the directory without allocating space.
554 */
555 int
556 xfs_dir_canenter(
557 xfs_trans_t *tp,
558 xfs_inode_t *dp,
559 struct xfs_name *name) /* name of entry to add */
560 {
561 return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0);
562 }
563
564 /*
565 * Utility routines.
566 */
567
568 /*
569 * Add a block to the directory.
570 *
571 * This routine is for data and free blocks, not leaf/node blocks which are
572 * handled by xfs_da_grow_inode.
573 */
574 int
575 xfs_dir2_grow_inode(
576 struct xfs_da_args *args,
577 int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */
578 xfs_dir2_db_t *dbp) /* out: block number added */
579 {
580 struct xfs_inode *dp = args->dp;
581 struct xfs_mount *mp = dp->i_mount;
582 xfs_fileoff_t bno; /* directory offset of new block */
583 int count; /* count of filesystem blocks */
584 int error;
585
586 trace_xfs_dir2_grow_inode(args, space);
587
588 /*
589 * Set lowest possible block in the space requested.
590 */
591 bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
592 count = args->geo->fsbcount;
593
594 error = xfs_da_grow_inode_int(args, &bno, count);
595 if (error)
596 return error;
597
598 *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);
599
600 /*
601 * Update file's size if this is the data space and it grew.
602 */
603 if (space == XFS_DIR2_DATA_SPACE) {
604 xfs_fsize_t size; /* directory file (data) size */
605
606 size = XFS_FSB_TO_B(mp, bno + count);
607 if (size > dp->i_d.di_size) {
608 dp->i_d.di_size = size;
609 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
610 }
611 }
612 return 0;
613 }
614
615 /*
616 * See if the directory is a single-block form directory.
617 */
618 int
619 xfs_dir2_isblock(
620 struct xfs_da_args *args,
621 int *vp) /* out: 1 is block, 0 is not block */
622 {
623 xfs_fileoff_t last; /* last file offset */
624 int rval;
625
626 if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
627 return rval;
628 rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
629 if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize)
630 return -EFSCORRUPTED;
631 *vp = rval;
632 return 0;
633 }
634
635 /*
636 * See if the directory is a single-leaf form directory.
637 */
638 int
639 xfs_dir2_isleaf(
640 struct xfs_da_args *args,
641 int *vp) /* out: 1 is block, 0 is not block */
642 {
643 xfs_fileoff_t last; /* last file offset */
644 int rval;
645
646 if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
647 return rval;
648 *vp = last == args->geo->leafblk + args->geo->fsbcount;
649 return 0;
650 }
651
652 /*
653 * Remove the given block from the directory.
654 * This routine is used for data and free blocks, leaf/node are done
655 * by xfs_da_shrink_inode.
656 */
657 int
658 xfs_dir2_shrink_inode(
659 xfs_da_args_t *args,
660 xfs_dir2_db_t db,
661 struct xfs_buf *bp)
662 {
663 xfs_fileoff_t bno; /* directory file offset */
664 xfs_dablk_t da; /* directory file offset */
665 int done; /* bunmap is finished */
666 xfs_inode_t *dp;
667 int error;
668 xfs_mount_t *mp;
669 xfs_trans_t *tp;
670
671 trace_xfs_dir2_shrink_inode(args, db);
672
673 dp = args->dp;
674 mp = dp->i_mount;
675 tp = args->trans;
676 da = xfs_dir2_db_to_da(args->geo, db);
677
678 /* Unmap the fsblock(s). */
679 error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0,
680 args->firstblock, args->dfops, &done);
681 if (error) {
682 /*
683 * ENOSPC actually can happen if we're in a removename with no
684 * space reservation, and the resulting block removal would
685 * cause a bmap btree split or conversion from extents to btree.
686 * This can only happen for un-fragmented directory blocks,
687 * since you need to be punching out the middle of an extent.
688 * In this case we need to leave the block in the file, and not
689 * binval it. So the block has to be in a consistent empty
690 * state and appropriately logged. We don't free up the buffer,
691 * the caller can tell it hasn't happened since it got an error
692 * back.
693 */
694 return error;
695 }
696 ASSERT(done);
697 /*
698 * Invalidate the buffer from the transaction.
699 */
700 xfs_trans_binval(tp, bp);
701 /*
702 * If it's not a data block, we're done.
703 */
704 if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
705 return 0;
706 /*
707 * If the block isn't the last one in the directory, we're done.
708 */
709 if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))
710 return 0;
711 bno = da;
712 if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
713 /*
714 * This can't really happen unless there's kernel corruption.
715 */
716 return error;
717 }
718 if (db == args->geo->datablk)
719 ASSERT(bno == 0);
720 else
721 ASSERT(bno > 0);
722 /*
723 * Set the size to the new last block.
724 */
725 dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
726 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
727 return 0;
728 }